mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-17 20:51:20 +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:
committed by
Ian Storm Taylor
parent
f28c59a26e
commit
3339d088e1
93
.eslintrc
93
.eslintrc
@@ -1,8 +1,6 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"extends": ["prettier", "prettier/react"],
|
||||||
"import",
|
"plugins": ["import", "react", "prettier"],
|
||||||
"react"
|
|
||||||
],
|
|
||||||
"settings": {
|
"settings": {
|
||||||
"import/extensions": [".js"]
|
"import/extensions": [".js"]
|
||||||
},
|
},
|
||||||
@@ -18,19 +16,8 @@
|
|||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"rules": {
|
"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",
|
"constructor-super": "error",
|
||||||
"curly": ["error", "multi-line"],
|
|
||||||
"dot-location": ["error", "property"],
|
|
||||||
"dot-notation": ["error", { "allowKeywords": true }],
|
"dot-notation": ["error", { "allowKeywords": true }],
|
||||||
"eol-last": "error",
|
|
||||||
"func-call-spacing": ["error", "never"],
|
|
||||||
"import/default": "error",
|
"import/default": "error",
|
||||||
"import/export": "error",
|
"import/export": "error",
|
||||||
"import/first": "error",
|
"import/first": "error",
|
||||||
@@ -38,18 +25,25 @@
|
|||||||
"import/namespace": "error",
|
"import/namespace": "error",
|
||||||
"import/newline-after-import": "error",
|
"import/newline-after-import": "error",
|
||||||
"import/no-deprecated": "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-mutable-exports": "error",
|
||||||
"import/no-named-as-default": "error",
|
"import/no-named-as-default": "error",
|
||||||
"import/no-named-as-default-member": "error",
|
"import/no-named-as-default-member": "error",
|
||||||
"import/no-unresolved": "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",
|
"linebreak-style": "error",
|
||||||
"lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": true, "allowBlockStart": true, "allowObjectStart": true, "allowArrayStart": true }],
|
"lines-around-comment": [
|
||||||
"new-parens": "error",
|
"error",
|
||||||
|
{
|
||||||
|
"beforeBlockComment": true,
|
||||||
|
"afterBlockComment": true,
|
||||||
|
"allowBlockStart": true,
|
||||||
|
"allowObjectStart": true,
|
||||||
|
"allowArrayStart": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"no-array-constructor": "error",
|
"no-array-constructor": "error",
|
||||||
"no-class-assign": "error",
|
"no-class-assign": "error",
|
||||||
"no-console": "error",
|
"no-console": "error",
|
||||||
@@ -68,9 +62,6 @@
|
|||||||
"no-func-assign": "error",
|
"no-func-assign": "error",
|
||||||
"no-invalid-regexp": "error",
|
"no-invalid-regexp": "error",
|
||||||
"no-lonely-if": "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-native-reassign": "error",
|
||||||
"no-negated-in-lhs": "error",
|
"no-negated-in-lhs": "error",
|
||||||
"no-new-object": "error",
|
"no-new-object": "error",
|
||||||
@@ -78,15 +69,29 @@
|
|||||||
"no-path-concat": "error",
|
"no-path-concat": "error",
|
||||||
"no-redeclare": "error",
|
"no-redeclare": "error",
|
||||||
"no-regex-spaces": "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-sequences": "error",
|
||||||
"no-shadow": "error",
|
"no-shadow": "error",
|
||||||
"no-shadow-restricted-names": "error",
|
"no-shadow-restricted-names": "error",
|
||||||
"no-spaced-func": "error",
|
|
||||||
"no-tabs": "error",
|
"no-tabs": "error",
|
||||||
"no-this-before-super": "error",
|
"no-this-before-super": "error",
|
||||||
"no-throw-literal": "error",
|
"no-throw-literal": "error",
|
||||||
"no-trailing-spaces": "error",
|
|
||||||
"no-undef": "error",
|
"no-undef": "error",
|
||||||
"no-unneeded-ternary": "error",
|
"no-unneeded-ternary": "error",
|
||||||
"no-unreachable": "error",
|
"no-unreachable": "error",
|
||||||
@@ -100,31 +105,24 @@
|
|||||||
"no-useless-rename": "error",
|
"no-useless-rename": "error",
|
||||||
"no-var": "error",
|
"no-var": "error",
|
||||||
"no-void": "error",
|
"no-void": "error",
|
||||||
"no-whitespace-before-property": "error",
|
|
||||||
"no-with": "error",
|
"no-with": "error",
|
||||||
"object-curly-spacing": ["error", "always", { "objectsInObjects": false }],
|
|
||||||
"object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
|
|
||||||
"object-shorthand": ["error", "always"],
|
"object-shorthand": ["error", "always"],
|
||||||
"operator-linebreak": ["error", "after", { "overrides": { "?": "ignore", ":": "ignore" }}],
|
|
||||||
"padded-blocks": ["error", { "blocks": "never", "classes": "always" }],
|
|
||||||
"prefer-arrow-callback": "error",
|
"prefer-arrow-callback": "error",
|
||||||
"prefer-const": ["error", { "destructuring": "all", "ignoreReadBeforeAssign": true }],
|
"prefer-const": [
|
||||||
|
"error",
|
||||||
|
{ "destructuring": "all", "ignoreReadBeforeAssign": true }
|
||||||
|
],
|
||||||
"prefer-rest-params": "error",
|
"prefer-rest-params": "error",
|
||||||
"prefer-spread": "error",
|
"prefer-spread": "error",
|
||||||
"prefer-template": "error",
|
"prefer-template": "error",
|
||||||
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
|
"prettier/prettier": "error",
|
||||||
"radix": "error",
|
"radix": "error",
|
||||||
"react/jsx-boolean-value": ["error", "never"],
|
"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-key": "error",
|
||||||
"react/jsx-no-bind": "error",
|
"react/jsx-no-bind": "error",
|
||||||
"react/jsx-no-duplicate-props": "error",
|
"react/jsx-no-duplicate-props": "error",
|
||||||
"react/jsx-no-target-blank": "error",
|
"react/jsx-no-target-blank": "error",
|
||||||
"react/jsx-no-undef": "error",
|
"react/jsx-no-undef": "error",
|
||||||
"react/jsx-tag-spacing": ["error", { "beforeSelfClosing": "always" }],
|
|
||||||
"react/jsx-uses-react": "error",
|
"react/jsx-uses-react": "error",
|
||||||
"react/jsx-uses-vars": "error",
|
"react/jsx-uses-vars": "error",
|
||||||
"react/jsx-wrap-multilines": "error",
|
"react/jsx-wrap-multilines": "error",
|
||||||
@@ -136,19 +134,12 @@
|
|||||||
"react/react-in-jsx-scope": "error",
|
"react/react-in-jsx-scope": "error",
|
||||||
"react/self-closing-comp": "error",
|
"react/self-closing-comp": "error",
|
||||||
"react/sort-prop-types": "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": ["-"] }],
|
"spaced-comment": ["error", "always", { "exceptions": ["-"] }],
|
||||||
"template-curly-spacing": "error",
|
|
||||||
"template-tag-spacing": ["error", "never"],
|
|
||||||
"unicode-bom": ["error", "never"],
|
|
||||||
"use-isnan": "error",
|
"use-isnan": "error",
|
||||||
"valid-jsdoc": ["error", { "prefer": { "return": "returns" }, "requireReturn": false }],
|
"valid-jsdoc": [
|
||||||
|
"error",
|
||||||
|
{ "prefer": { "return": "returns" }, "requireReturn": false }
|
||||||
|
],
|
||||||
"valid-typeof": "error",
|
"valid-typeof": "error",
|
||||||
"yield-star-spacing": ["error", "after"],
|
"yield-star-spacing": ["error", "after"],
|
||||||
"yoda": ["error", "never"]
|
"yoda": ["error", "never"]
|
||||||
|
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
examples/build.prod.js
|
||||||
|
package.json
|
||||||
|
packages/*/dist/
|
||||||
|
packages/*/lib/
|
||||||
|
tmp/
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -12,14 +11,13 @@ import initialValue from './value.json'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class CheckListItem extends React.Component {
|
class CheckListItem extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On change, set the new checked value on the block.
|
* On change, set the new checked value on the block.
|
||||||
*
|
*
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onChange = (event) => {
|
onChange = event => {
|
||||||
const checked = event.target.checked
|
const checked = event.target.checked
|
||||||
const { editor, node } = this.props
|
const { editor, node } = this.props
|
||||||
editor.change(c => c.setNodeByKey(node.key, { data: { checked } }))
|
editor.change(c => c.setNodeByKey(node.key, { data: { checked } }))
|
||||||
@@ -42,11 +40,7 @@ class CheckListItem extends React.Component {
|
|||||||
{...attributes}
|
{...attributes}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
<input
|
<input type="checkbox" checked={checked} onChange={this.onChange} />
|
||||||
type="checkbox"
|
|
||||||
checked={checked}
|
|
||||||
onChange={this.onChange}
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
<span contentEditable suppressContentEditableWarning>
|
<span contentEditable suppressContentEditableWarning>
|
||||||
{children}
|
{children}
|
||||||
@@ -54,7 +48,6 @@ class CheckListItem extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +57,6 @@ class CheckListItem extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class CheckLists extends React.Component {
|
class CheckLists extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -72,7 +64,7 @@ class CheckLists extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -102,10 +94,7 @@ class CheckLists extends React.Component {
|
|||||||
onKeyDown = (event, change) => {
|
onKeyDown = (event, change) => {
|
||||||
const { value } = change
|
const { value } = change
|
||||||
|
|
||||||
if (
|
if (event.key == 'Enter' && value.startBlock.type == 'check-list-item') {
|
||||||
event.key == 'Enter' &&
|
|
||||||
value.startBlock.type == 'check-list-item'
|
|
||||||
) {
|
|
||||||
change.splitBlock().setBlock({ data: { checked: false } })
|
change.splitBlock().setBlock({ data: { checked: false } })
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -151,12 +140,12 @@ class CheckLists extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
switch (props.node.type) {
|
switch (props.node.type) {
|
||||||
case 'check-list-item': return <CheckListItem {...props} />
|
case 'check-list-item':
|
||||||
|
return <CheckListItem {...props} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -18,7 +17,9 @@ function CodeBlock(props) {
|
|||||||
const language = node.data.get('language')
|
const language = node.data.get('language')
|
||||||
|
|
||||||
function onChange(event) {
|
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 (
|
return (
|
||||||
@@ -41,9 +42,7 @@ function CodeBlock(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function CodeBlockLine(props) {
|
function CodeBlockLine(props) {
|
||||||
return (
|
return <div {...props.attributes}>{props.children}</div>
|
||||||
<div {...props.attributes}>{props.children}</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +52,6 @@ function CodeBlockLine(props) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class CodeHighlighting extends React.Component {
|
class CodeHighlighting extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -61,7 +59,7 @@ class CodeHighlighting extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,10 +119,12 @@ class CodeHighlighting extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
switch (props.node.type) {
|
switch (props.node.type) {
|
||||||
case 'code': return <CodeBlock {...props} />
|
case 'code':
|
||||||
case 'code_line': return <CodeBlockLine {...props} />
|
return <CodeBlock {...props} />
|
||||||
|
case 'code_line':
|
||||||
|
return <CodeBlockLine {...props} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,17 +135,21 @@ class CodeHighlighting extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'comment': return <span style={{ opacity: '0.33' }}>{children}</span>
|
case 'comment':
|
||||||
case 'keyword': return <span style={{ fontWeight: 'bold' }}>{children}</span>
|
return <span style={{ opacity: '0.33' }}>{children}</span>
|
||||||
case 'tag': return <span style={{ fontWeight: 'bold' }}>{children}</span>
|
case 'keyword':
|
||||||
case 'punctuation': return <span style={{ opacity: '0.75' }}>{children}</span>
|
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') {
|
if (typeof token == 'string') {
|
||||||
return token
|
return token
|
||||||
} else if (typeof token.content == 'string') {
|
} else if (typeof token.content == 'string') {
|
||||||
@@ -162,7 +166,7 @@ class CodeHighlighting extends React.Component {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
decorateNode = (node) => {
|
decorateNode = node => {
|
||||||
if (node.type != 'code') return
|
if (node.type != 'code') return
|
||||||
|
|
||||||
const language = node.data.get('language')
|
const language = node.data.get('language')
|
||||||
@@ -215,7 +219,6 @@ class CodeHighlighting extends React.Component {
|
|||||||
|
|
||||||
return decorations
|
return decorations
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -13,7 +12,6 @@ import initialValue from './value.json'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Embeds extends React.Component {
|
class Embeds extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -21,7 +19,7 @@ class Embeds extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,12 +58,12 @@ class Embeds extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
switch (props.node.type) {
|
switch (props.node.type) {
|
||||||
case 'video': return <Video {...props} />
|
case 'video':
|
||||||
|
return <Video {...props} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8,14 +7,13 @@ import React from 'react'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Video extends React.Component {
|
class Video extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the input text changes, update the `video` data on the node.
|
* When the input text changes, update the `video` data on the node.
|
||||||
*
|
*
|
||||||
* @param {Event} e
|
* @param {Event} e
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onChange = (e) => {
|
onChange = e => {
|
||||||
const video = e.target.value
|
const video = e.target.value
|
||||||
const { node, editor } = this.props
|
const { node, editor } = this.props
|
||||||
editor.change(c => c.setNodeByKey(node.key, { data: { video } }))
|
editor.change(c => c.setNodeByKey(node.key, { data: { video } }))
|
||||||
@@ -28,7 +26,7 @@ class Video extends React.Component {
|
|||||||
* @type {Event} e
|
* @type {Event} e
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onClick = (e) => {
|
onClick = e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +72,7 @@ class Video extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const iframeStyle = {
|
const iframeStyle = {
|
||||||
display: 'block'
|
display: 'block',
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -104,7 +102,7 @@ class Video extends React.Component {
|
|||||||
const video = node.data.get('video')
|
const video = node.data.get('video')
|
||||||
const style = {
|
const style = {
|
||||||
marginTop: '5px',
|
marginTop: '5px',
|
||||||
boxSizing: 'border-box'
|
boxSizing: 'border-box',
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -116,7 +114,6 @@ class Video extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -12,9 +11,24 @@ import initialValue from './value.json'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const EMOJIS = [
|
const EMOJIS = [
|
||||||
'😃', '😬', '😂', '😅', '😆', '😍',
|
'😃',
|
||||||
'😱', '👋', '👏', '👍', '🙌', '👌',
|
'😬',
|
||||||
'🙏', '👻', '🍔', '🍑', '🍆', '🔑',
|
'😂',
|
||||||
|
'😅',
|
||||||
|
'😆',
|
||||||
|
'😍',
|
||||||
|
'😱',
|
||||||
|
'👋',
|
||||||
|
'👏',
|
||||||
|
'👍',
|
||||||
|
'🙌',
|
||||||
|
'👌',
|
||||||
|
'🙏',
|
||||||
|
'👻',
|
||||||
|
'🍔',
|
||||||
|
'🍑',
|
||||||
|
'🍆',
|
||||||
|
'🔑',
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +46,6 @@ const noop = e => e.preventDefault()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Emojis extends React.Component {
|
class Emojis extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -40,7 +53,7 @@ class Emojis extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +80,7 @@ class Emojis extends React.Component {
|
|||||||
change.insertInline({
|
change.insertInline({
|
||||||
type: 'emoji',
|
type: 'emoji',
|
||||||
isVoid: true,
|
isVoid: true,
|
||||||
data: { code }
|
data: { code },
|
||||||
})
|
})
|
||||||
|
|
||||||
this.onChange(change)
|
this.onChange(change)
|
||||||
@@ -136,7 +149,7 @@ class Emojis extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node, isSelected } = props
|
const { attributes, children, node, isSelected } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'paragraph': {
|
case 'paragraph': {
|
||||||
@@ -158,7 +171,6 @@ class Emojis extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Block, Value } from 'slate'
|
import { Block, Value } from 'slate'
|
||||||
import { CHILD_REQUIRED, CHILD_TYPE_INVALID } from 'slate-schema-violations'
|
import { CHILD_REQUIRED, CHILD_TYPE_INVALID } from 'slate-schema-violations'
|
||||||
@@ -21,15 +20,18 @@ const schema = {
|
|||||||
normalize: (change, violation, { node, child, index }) => {
|
normalize: (change, violation, { node, child, index }) => {
|
||||||
switch (violation) {
|
switch (violation) {
|
||||||
case CHILD_TYPE_INVALID: {
|
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: {
|
case CHILD_REQUIRED: {
|
||||||
const block = Block.create(index == 0 ? 'title' : 'paragraph')
|
const block = Block.create(index == 0 ? 'title' : 'paragraph')
|
||||||
return change.insertNodeByKey(node.key, index, block)
|
return change.insertNodeByKey(node.key, index, block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,7 +41,6 @@ const schema = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class ForcedLayout extends React.Component {
|
class ForcedLayout extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -87,14 +88,15 @@ class ForcedLayout extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node } = props
|
const { attributes, children, node } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'title': return <h2 {...attributes}>{children}</h2>
|
case 'title':
|
||||||
case 'paragraph': return <p {...attributes}>{children}</p>
|
return <h2 {...attributes}>{children}</h2>
|
||||||
|
case 'paragraph':
|
||||||
|
return <p {...attributes}>{children}</p>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
|
|
||||||
@@ -24,7 +23,6 @@ const ToolbarButton = props => (
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class History extends React.Component {
|
class History extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -32,7 +30,7 @@ class History extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +48,7 @@ class History extends React.Component {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onClickRedo = (event) => {
|
onClickRedo = event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
const change = value.change().redo()
|
const change = value.change().redo()
|
||||||
@@ -62,7 +60,7 @@ class History extends React.Component {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onClickUndo = (event) => {
|
onClickUndo = event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
const change = value.change().undo()
|
const change = value.change().undo()
|
||||||
@@ -96,12 +94,8 @@ class History extends React.Component {
|
|||||||
<div className="menu toolbar-menu">
|
<div className="menu toolbar-menu">
|
||||||
<ToolbarButton icon="undo" onMouseDown={this.onClickUndo} />
|
<ToolbarButton icon="undo" onMouseDown={this.onClickUndo} />
|
||||||
<ToolbarButton icon="redo" onMouseDown={this.onClickRedo} />
|
<ToolbarButton icon="redo" onMouseDown={this.onClickRedo} />
|
||||||
<span className="button">
|
<span className="button">Undos: {value.history.undos.size}</span>
|
||||||
Undos: {value.history.undos.size}
|
<span className="button">Redos: {value.history.redos.size}</span>
|
||||||
</span>
|
|
||||||
<span className="button">
|
|
||||||
Redos: {value.history.redos.size}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -123,7 +117,6 @@ class History extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -15,7 +14,6 @@ const root = window.document.querySelector('main')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Menu extends React.Component {
|
class Menu extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current selection has a mark with `type` in it.
|
* Check if the current selection has a mark with `type` in it.
|
||||||
*
|
*
|
||||||
@@ -69,8 +67,7 @@ class Menu extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return ReactDOM.createPortal(
|
||||||
ReactDOM.createPortal(
|
|
||||||
<div className="menu hover-menu" ref={this.props.menuRef}>
|
<div className="menu hover-menu" ref={this.props.menuRef}>
|
||||||
{this.renderMarkButton('bold', 'format_bold')}
|
{this.renderMarkButton('bold', 'format_bold')}
|
||||||
{this.renderMarkButton('italic', 'format_italic')}
|
{this.renderMarkButton('italic', 'format_italic')}
|
||||||
@@ -79,12 +76,9 @@ class Menu extends React.Component {
|
|||||||
</div>,
|
</div>,
|
||||||
root
|
root
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The hovering menu example.
|
* The hovering menu example.
|
||||||
*
|
*
|
||||||
@@ -92,7 +86,6 @@ class Menu extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class HoveringMenu extends React.Component {
|
class HoveringMenu extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -100,7 +93,7 @@ class HoveringMenu extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,7 +127,10 @@ class HoveringMenu extends React.Component {
|
|||||||
const rect = range.getBoundingClientRect()
|
const rect = range.getBoundingClientRect()
|
||||||
menu.style.opacity = 1
|
menu.style.opacity = 1
|
||||||
menu.style.top = `${rect.top + window.scrollY - menu.offsetHeight}px`
|
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
|
* @param {Menu} menu
|
||||||
*/
|
*/
|
||||||
|
|
||||||
menuRef = (menu) => {
|
menuRef = menu => {
|
||||||
this.menu = menu
|
this.menu = menu
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,16 +186,19 @@ class HoveringMenu extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'bold': return <strong>{children}</strong>
|
case 'bold':
|
||||||
case 'code': return <code>{children}</code>
|
return <strong>{children}</strong>
|
||||||
case 'italic': return <em>{children}</em>
|
case 'code':
|
||||||
case 'underlined': return <u>{children}</u>
|
return <code>{children}</code>
|
||||||
|
case 'italic':
|
||||||
|
return <em>{children}</em>
|
||||||
|
case 'underlined':
|
||||||
|
return <u>{children}</u>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -16,21 +16,21 @@ const HEADINGS = 100
|
|||||||
const PARAGRAPHS = 8 // Paragraphs per heading
|
const PARAGRAPHS = 8 // Paragraphs per heading
|
||||||
const nodes = []
|
const nodes = []
|
||||||
const json = {
|
const json = {
|
||||||
document: { nodes }
|
document: { nodes },
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let h = 0; h < HEADINGS; h++) {
|
for (let h = 0; h < HEADINGS; h++) {
|
||||||
nodes.push({
|
nodes.push({
|
||||||
object: 'block',
|
object: 'block',
|
||||||
type: 'heading',
|
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++) {
|
for (let p = 0; p < PARAGRAPHS; p++) {
|
||||||
nodes.push({
|
nodes.push({
|
||||||
object: 'block',
|
object: 'block',
|
||||||
type: 'paragraph',
|
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 {
|
class HugeDocument extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -95,10 +94,11 @@ class HugeDocument extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node } = props
|
const { attributes, children, node } = props
|
||||||
switch (node.type) {
|
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}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'bold': return <strong>{children}</strong>
|
case 'bold':
|
||||||
case 'code': return <code>{children}</code>
|
return <strong>{children}</strong>
|
||||||
case 'italic': return <em>{children}</em>
|
case 'code':
|
||||||
case 'underlined': return <u>{children}</u>
|
return <code>{children}</code>
|
||||||
|
case 'italic':
|
||||||
|
return <em>{children}</em>
|
||||||
|
case 'underlined':
|
||||||
|
return <u>{children}</u>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor, getEventRange, getEventTransfer } from 'slate-react'
|
import { Editor, getEventRange, getEventTransfer } from 'slate-react'
|
||||||
import { Block, Value } from 'slate'
|
import { Block, Value } from 'slate'
|
||||||
import { LAST_CHILD_TYPE_INVALID } from 'slate-schema-violations'
|
import { LAST_CHILD_TYPE_INVALID } from 'slate-schema-violations'
|
||||||
@@ -35,7 +34,7 @@ function insertImage(change, src, target) {
|
|||||||
change.insertBlock({
|
change.insertBlock({
|
||||||
type: 'image',
|
type: 'image',
|
||||||
isVoid: true,
|
isVoid: true,
|
||||||
data: { src }
|
data: { src },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +54,8 @@ const schema = {
|
|||||||
return change.insertNodeByKey(node.key, node.nodes.size, paragraph)
|
return change.insertNodeByKey(node.key, node.nodes.size, paragraph)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +65,6 @@ const schema = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Images extends React.Component {
|
class Images extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -74,7 +72,7 @@ class Images extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,7 +135,7 @@ class Images extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, node, isSelected } = props
|
const { attributes, node, isSelected } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'image': {
|
case 'image': {
|
||||||
@@ -167,14 +165,12 @@ class Images extends React.Component {
|
|||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onClickImage = (event) => {
|
onClickImage = event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const src = window.prompt('Enter the URL of the image:')
|
const src = window.prompt('Enter the URL of the image:')
|
||||||
if (!src) return
|
if (!src) return
|
||||||
|
|
||||||
const change = this.state.value
|
const change = this.state.value.change().call(insertImage, src)
|
||||||
.change()
|
|
||||||
.call(insertImage, src)
|
|
||||||
|
|
||||||
this.onChange(change)
|
this.onChange(change)
|
||||||
}
|
}
|
||||||
@@ -201,7 +197,7 @@ class Images extends React.Component {
|
|||||||
if (mime != 'image') continue
|
if (mime != 'image') continue
|
||||||
|
|
||||||
reader.addEventListener('load', () => {
|
reader.addEventListener('load', () => {
|
||||||
editor.change((c) => {
|
editor.change(c => {
|
||||||
c.call(insertImage, reader.result, target)
|
c.call(insertImage, reader.result, target)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -216,7 +212,6 @@ class Images extends React.Component {
|
|||||||
change.call(insertImage, text, target)
|
change.call(insertImage, text, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { HashRouter, NavLink, Route, Redirect, Switch } from 'react-router-dom'
|
import { HashRouter, NavLink, Route, Redirect, Switch } from 'react-router-dom'
|
||||||
@@ -62,7 +61,6 @@ const EXAMPLES = [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
error: null,
|
error: null,
|
||||||
info: null,
|
info: null,
|
||||||
@@ -78,20 +76,30 @@ class App extends React.Component {
|
|||||||
<div className="nav">
|
<div className="nav">
|
||||||
<span className="nav-title">Slate Examples</span>
|
<span className="nav-title">Slate Examples</span>
|
||||||
<div className="nav-links">
|
<div className="nav-links">
|
||||||
<a className="nav-link" href="https://github.com/ianstormtaylor/slate">GitHub</a>
|
<a
|
||||||
<a className="nav-link" href="https://docs.slatejs.org/">Docs</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>
|
</div>
|
||||||
<div className="tabs">
|
<div className="tabs">
|
||||||
{EXAMPLES.map(([name, Component, path]) => (
|
{EXAMPLES.map(([name, Component, path]) => (
|
||||||
<NavLink key={path} to={path} className="tab"activeClassName="active">
|
<NavLink
|
||||||
|
key={path}
|
||||||
|
to={path}
|
||||||
|
className="tab"
|
||||||
|
activeClassName="active"
|
||||||
|
>
|
||||||
{name}
|
{name}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{this.state.error
|
{this.state.error ? this.renderError() : this.renderExample()}
|
||||||
? this.renderError()
|
|
||||||
: this.renderExample()}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -112,9 +120,7 @@ class App extends React.Component {
|
|||||||
renderError() {
|
renderError() {
|
||||||
return (
|
return (
|
||||||
<div className="error">
|
<div className="error">
|
||||||
<p>
|
<p>An error was thrown by one of the example's React components!</p>
|
||||||
An error was thrown by one of the example's React components!
|
|
||||||
</p>
|
|
||||||
<pre className="info">
|
<pre className="info">
|
||||||
<code>
|
<code>
|
||||||
{this.state.error.stack}
|
{this.state.error.stack}
|
||||||
@@ -125,7 +131,6 @@ class App extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,7 +139,11 @@ class App extends React.Component {
|
|||||||
* @type {Element} router
|
* @type {Element} router
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const router = <HashRouter><App /></HashRouter>
|
const router = (
|
||||||
|
<HashRouter>
|
||||||
|
<App />
|
||||||
|
</HashRouter>
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mount the router.
|
* Mount the router.
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor, getEventTransfer } from 'slate-react'
|
import { Editor, getEventTransfer } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -16,7 +15,7 @@ import isUrl from 'is-url'
|
|||||||
function wrapLink(change, href) {
|
function wrapLink(change, href) {
|
||||||
change.wrapInline({
|
change.wrapInline({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
data: { href }
|
data: { href },
|
||||||
})
|
})
|
||||||
|
|
||||||
change.collapseToEnd()
|
change.collapseToEnd()
|
||||||
@@ -39,7 +38,6 @@ function unwrapLink(change) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Links extends React.Component {
|
class Links extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -47,7 +45,7 @@ class Links extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +76,7 @@ class Links extends React.Component {
|
|||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onClickLink = (event) => {
|
onClickLink = event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
const hasLinks = this.hasLinks()
|
const hasLinks = this.hasLinks()
|
||||||
@@ -86,14 +84,10 @@ class Links extends React.Component {
|
|||||||
|
|
||||||
if (hasLinks) {
|
if (hasLinks) {
|
||||||
change.call(unwrapLink)
|
change.call(unwrapLink)
|
||||||
}
|
} else if (value.isExpanded) {
|
||||||
|
|
||||||
else if (value.isExpanded) {
|
|
||||||
const href = window.prompt('Enter the URL of the link:')
|
const href = window.prompt('Enter the URL of the link:')
|
||||||
change.call(wrapLink, href)
|
change.call(wrapLink, href)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
else {
|
|
||||||
const href = window.prompt('Enter the URL of the link:')
|
const href = window.prompt('Enter the URL of the link:')
|
||||||
const text = window.prompt('Enter the text for the link:')
|
const text = window.prompt('Enter the text for the link:')
|
||||||
change
|
change
|
||||||
@@ -153,7 +147,11 @@ class Links extends React.Component {
|
|||||||
const hasLinks = this.hasLinks()
|
const hasLinks = this.hasLinks()
|
||||||
return (
|
return (
|
||||||
<div className="menu toolbar-menu">
|
<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 className="material-icons">link</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -187,17 +185,20 @@ class Links extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node } = props
|
const { attributes, children, node } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'link': {
|
case 'link': {
|
||||||
const { data } = node
|
const { data } = node
|
||||||
const href = data.get('href')
|
const href = data.get('href')
|
||||||
return <a {...attributes} href={href}>{children}</a>
|
return (
|
||||||
|
<a {...attributes} href={href}>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Plain from 'slate-plain-serializer'
|
import Plain from 'slate-plain-serializer'
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
|
|
||||||
@@ -10,7 +9,7 @@ import React from 'react'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// 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.
|
* The markdown preview example.
|
||||||
@@ -19,7 +18,6 @@ Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.ins
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class MarkdownPreview extends React.Component {
|
class MarkdownPreview extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -27,7 +25,9 @@ class MarkdownPreview extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
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}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'bold': return <strong>{children}</strong>
|
case 'bold':
|
||||||
case 'code': return <code>{children}</code>
|
return <strong>{children}</strong>
|
||||||
case 'italic': return <em>{children}</em>
|
case 'code':
|
||||||
case 'underlined': return <u>{children}</u>
|
return <code>{children}</code>
|
||||||
|
case 'italic':
|
||||||
|
return <em>{children}</em>
|
||||||
|
case 'underlined':
|
||||||
|
return <u>{children}</u>
|
||||||
case 'title': {
|
case 'title': {
|
||||||
return (
|
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}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'punctuation': {
|
case 'punctuation': {
|
||||||
return (
|
return <span style={{ opacity: 0.2 }}>{children}</span>
|
||||||
<span style={{ opacity: 0.2 }}>
|
|
||||||
{children}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
case 'list': {
|
case 'list': {
|
||||||
return (
|
return (
|
||||||
<span style={{ paddingLeft: '10px', lineHeight: '10px', fontSize: '20px' }}>
|
<span
|
||||||
|
style={{
|
||||||
|
paddingLeft: '10px',
|
||||||
|
lineHeight: '10px',
|
||||||
|
fontSize: '20px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case 'hr': {
|
case 'hr': {
|
||||||
return (
|
return (
|
||||||
<span style={{ borderBottom: '2px solid #000', display: 'block', opacity: 0.2 }}>
|
<span
|
||||||
|
style={{
|
||||||
|
borderBottom: '2px solid #000',
|
||||||
|
display: 'block',
|
||||||
|
opacity: 0.2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
@@ -168,13 +187,11 @@ class MarkdownPreview extends React.Component {
|
|||||||
decorations.push(range)
|
decorations.push(range)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
start = end
|
start = end
|
||||||
}
|
}
|
||||||
|
|
||||||
return decorations
|
return decorations
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -12,7 +11,6 @@ import initialValue from './value.json'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class MarkdownShortcuts extends React.Component {
|
class MarkdownShortcuts extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -20,7 +18,7 @@ class MarkdownShortcuts extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,19 +28,28 @@ class MarkdownShortcuts extends React.Component {
|
|||||||
* @return {String} block
|
* @return {String} block
|
||||||
*/
|
*/
|
||||||
|
|
||||||
getType = (chars) => {
|
getType = chars => {
|
||||||
switch (chars) {
|
switch (chars) {
|
||||||
case '*':
|
case '*':
|
||||||
case '-':
|
case '-':
|
||||||
case '+': return 'list-item'
|
case '+':
|
||||||
case '>': return 'block-quote'
|
return 'list-item'
|
||||||
case '#': return 'heading-one'
|
case '>':
|
||||||
case '##': return 'heading-two'
|
return 'block-quote'
|
||||||
case '###': return 'heading-three'
|
case '#':
|
||||||
case '####': return 'heading-four'
|
return 'heading-one'
|
||||||
case '#####': return 'heading-five'
|
case '##':
|
||||||
case '######': return 'heading-six'
|
return 'heading-two'
|
||||||
default: return null
|
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}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node } = props
|
const { attributes, children, node } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'block-quote': return <blockquote {...attributes}>{children}</blockquote>
|
case 'block-quote':
|
||||||
case 'bulleted-list': return <ul {...attributes}>{children}</ul>
|
return <blockquote {...attributes}>{children}</blockquote>
|
||||||
case 'heading-one': return <h1 {...attributes}>{children}</h1>
|
case 'bulleted-list':
|
||||||
case 'heading-two': return <h2 {...attributes}>{children}</h2>
|
return <ul {...attributes}>{children}</ul>
|
||||||
case 'heading-three': return <h3 {...attributes}>{children}</h3>
|
case 'heading-one':
|
||||||
case 'heading-four': return <h4 {...attributes}>{children}</h4>
|
return <h1 {...attributes}>{children}</h1>
|
||||||
case 'heading-five': return <h5 {...attributes}>{children}</h5>
|
case 'heading-two':
|
||||||
case 'heading-six': return <h6 {...attributes}>{children}</h6>
|
return <h2 {...attributes}>{children}</h2>
|
||||||
case 'list-item': return <li {...attributes}>{children}</li>
|
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) => {
|
onKeyDown = (event, change) => {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case ' ': return this.onSpace(event, change)
|
case ' ':
|
||||||
case 'Backspace': return this.onBackspace(event, change)
|
return this.onSpace(event, change)
|
||||||
case 'Enter': return this.onEnter(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
|
if (value.isExpanded) return
|
||||||
|
|
||||||
const { startBlock, startOffset, endOffset } = value
|
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 (endOffset != startBlock.text.length) return
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -202,7 +222,6 @@ class MarkdownShortcuts extends React.Component {
|
|||||||
change.splitBlock().setBlock('paragraph')
|
change.splitBlock().setBlock('paragraph')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Html from 'slate-html-serializer'
|
import Html from 'slate-html-serializer'
|
||||||
import { Editor, getEventTransfer } from 'slate-react'
|
import { Editor, getEventTransfer } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
@@ -24,7 +23,7 @@ const BLOCK_TAGS = {
|
|||||||
h3: 'heading-three',
|
h3: 'heading-three',
|
||||||
h4: 'heading-four',
|
h4: 'heading-four',
|
||||||
h5: 'heading-five',
|
h5: 'heading-five',
|
||||||
h6: 'heading-six'
|
h6: 'heading-six',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +37,7 @@ const MARK_TAGS = {
|
|||||||
em: 'italic',
|
em: 'italic',
|
||||||
u: 'underline',
|
u: 'underline',
|
||||||
s: 'strikethrough',
|
s: 'strikethrough',
|
||||||
code: 'code'
|
code: 'code',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,10 +54,10 @@ const RULES = [
|
|||||||
return {
|
return {
|
||||||
object: 'block',
|
object: 'block',
|
||||||
type: block,
|
type: block,
|
||||||
nodes: next(el.childNodes)
|
nodes: next(el.childNodes),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
deserialize(el, next) {
|
deserialize(el, next) {
|
||||||
const mark = MARK_TAGS[el.tagName.toLowerCase()]
|
const mark = MARK_TAGS[el.tagName.toLowerCase()]
|
||||||
@@ -66,26 +65,27 @@ const RULES = [
|
|||||||
return {
|
return {
|
||||||
object: 'mark',
|
object: 'mark',
|
||||||
type: mark,
|
type: mark,
|
||||||
nodes: next(el.childNodes)
|
nodes: next(el.childNodes),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Special case for code blocks, which need to grab the nested childNodes.
|
// Special case for code blocks, which need to grab the nested childNodes.
|
||||||
deserialize(el, next) {
|
deserialize(el, next) {
|
||||||
if (el.tagName.toLowerCase() != 'pre') return
|
if (el.tagName.toLowerCase() != 'pre') return
|
||||||
const code = el.childNodes[0]
|
const code = el.childNodes[0]
|
||||||
const childNodes = code && code.tagName.toLowerCase() == 'code'
|
const childNodes =
|
||||||
|
code && code.tagName.toLowerCase() == 'code'
|
||||||
? code.childNodes
|
? code.childNodes
|
||||||
: el.childNodes
|
: el.childNodes
|
||||||
|
|
||||||
return {
|
return {
|
||||||
object: 'block',
|
object: 'block',
|
||||||
type: 'code',
|
type: 'code',
|
||||||
nodes: next(childNodes)
|
nodes: next(childNodes),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Special case for images, to grab their src.
|
// Special case for images, to grab their src.
|
||||||
deserialize(el, next) {
|
deserialize(el, next) {
|
||||||
@@ -96,11 +96,11 @@ const RULES = [
|
|||||||
isVoid: true,
|
isVoid: true,
|
||||||
nodes: next(el.childNodes),
|
nodes: next(el.childNodes),
|
||||||
data: {
|
data: {
|
||||||
src: el.getAttribute('src')
|
src: el.getAttribute('src'),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Special case for links, to grab their href.
|
// Special case for links, to grab their href.
|
||||||
deserialize(el, next) {
|
deserialize(el, next) {
|
||||||
@@ -110,11 +110,11 @@ const RULES = [
|
|||||||
type: 'link',
|
type: 'link',
|
||||||
nodes: next(el.childNodes),
|
nodes: next(el.childNodes),
|
||||||
data: {
|
data: {
|
||||||
href: el.getAttribute('href')
|
href: el.getAttribute('href'),
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,7 +132,6 @@ const serializer = new Html({ rules: RULES })
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class PasteHtml extends React.Component {
|
class PasteHtml extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -140,7 +139,7 @@ class PasteHtml extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,24 +195,43 @@ class PasteHtml extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node, isSelected } = props
|
const { attributes, children, node, isSelected } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'quote': return <blockquote {...attributes}>{children}</blockquote>
|
case 'quote':
|
||||||
case 'code': return <pre><code {...attributes}>{children}</code></pre>
|
return <blockquote {...attributes}>{children}</blockquote>
|
||||||
case 'bulleted-list': return <ul {...attributes}>{children}</ul>
|
case 'code':
|
||||||
case 'heading-one': return <h1 {...attributes}>{children}</h1>
|
return (
|
||||||
case 'heading-two': return <h2 {...attributes}>{children}</h2>
|
<pre>
|
||||||
case 'heading-three': return <h3 {...attributes}>{children}</h3>
|
<code {...attributes}>{children}</code>
|
||||||
case 'heading-four': return <h4 {...attributes}>{children}</h4>
|
</pre>
|
||||||
case 'heading-five': return <h5 {...attributes}>{children}</h5>
|
)
|
||||||
case 'heading-six': return <h6 {...attributes}>{children}</h6>
|
case 'bulleted-list':
|
||||||
case 'list-item': return <li {...attributes}>{children}</li>
|
return <ul {...attributes}>{children}</ul>
|
||||||
case 'numbered-list': return <ol {...attributes}>{children}</ol>
|
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': {
|
case 'link': {
|
||||||
const { data } = node
|
const { data } = node
|
||||||
const href = data.get('href')
|
const href = data.get('href')
|
||||||
return <a href={href} {...attributes}>{children}</a>
|
return (
|
||||||
|
<a href={href} {...attributes}>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case 'image': {
|
case 'image': {
|
||||||
const src = node.data.get('src')
|
const src = node.data.get('src')
|
||||||
@@ -233,16 +251,19 @@ class PasteHtml extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'bold': return <strong>{children}</strong>
|
case 'bold':
|
||||||
case 'code': return <code>{children}</code>
|
return <strong>{children}</strong>
|
||||||
case 'italic': return <em>{children}</em>
|
case 'code':
|
||||||
case 'underlined': return <u>{children}</u>
|
return <code>{children}</code>
|
||||||
|
case 'italic':
|
||||||
|
return <em>{children}</em>
|
||||||
|
case 'underlined':
|
||||||
|
return <u>{children}</u>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Plain from 'slate-plain-serializer'
|
import Plain from 'slate-plain-serializer'
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import React from 'react'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class PlainText extends React.Component {
|
class PlainText extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -19,7 +17,9 @@ class PlainText extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Plain from 'slate-plain-serializer'
|
import Plain from 'slate-plain-serializer'
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
|
|
||||||
@@ -18,15 +17,13 @@ function WordCount(options) {
|
|||||||
renderEditor(props) {
|
renderEditor(props) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>{props.children}</div>
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
<span className="word-counter">
|
<span className="word-counter">
|
||||||
Word Count: {props.value.document.text.split(' ').length}
|
Word Count: {props.value.document.text.split(' ').length}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,11 +31,7 @@ function WordCount(options) {
|
|||||||
* Plugins.
|
* Plugins.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [CollapseOnEscape(), SoftBreak(), WordCount()]
|
||||||
CollapseOnEscape(),
|
|
||||||
SoftBreak(),
|
|
||||||
WordCount()
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The plugins example.
|
* The plugins example.
|
||||||
@@ -47,7 +40,6 @@ const plugins = [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Plugins extends React.Component {
|
class Plugins extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* 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!
|
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 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 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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Plain from 'slate-plain-serializer'
|
import Plain from 'slate-plain-serializer'
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ import React from 'react'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class ReadOnly extends React.Component {
|
class ReadOnly extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -19,7 +17,9 @@ class ReadOnly extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -32,7 +31,6 @@ const isCodeHotkey = isKeyHotkey('mod+`')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class RichTextExample extends React.Component {
|
class RichTextExample extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -50,7 +48,7 @@ class RichTextExample extends React.Component {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hasMark = (type) => {
|
hasMark = type => {
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
return value.activeMarks.some(mark => mark.type == type)
|
return value.activeMarks.some(mark => mark.type == type)
|
||||||
}
|
}
|
||||||
@@ -62,7 +60,7 @@ class RichTextExample extends React.Component {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hasBlock = (type) => {
|
hasBlock = type => {
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
return value.blocks.some(node => node.type == type)
|
return value.blocks.some(node => node.type == type)
|
||||||
}
|
}
|
||||||
@@ -142,18 +140,13 @@ class RichTextExample extends React.Component {
|
|||||||
.setBlock(isActive ? DEFAULT_NODE : type)
|
.setBlock(isActive ? DEFAULT_NODE : type)
|
||||||
.unwrapBlock('bulleted-list')
|
.unwrapBlock('bulleted-list')
|
||||||
.unwrapBlock('numbered-list')
|
.unwrapBlock('numbered-list')
|
||||||
|
} else {
|
||||||
|
change.setBlock(isActive ? DEFAULT_NODE : type)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
else {
|
|
||||||
change
|
|
||||||
.setBlock(isActive ? DEFAULT_NODE : type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the extra wrapping required for list buttons.
|
// Handle the extra wrapping required for list buttons.
|
||||||
else {
|
|
||||||
const isList = this.hasBlock('list-item')
|
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)
|
return !!document.getClosest(block.key, parent => parent.type == type)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -164,12 +157,12 @@ class RichTextExample extends React.Component {
|
|||||||
.unwrapBlock('numbered-list')
|
.unwrapBlock('numbered-list')
|
||||||
} else if (isList) {
|
} else if (isList) {
|
||||||
change
|
change
|
||||||
.unwrapBlock(type == 'bulleted-list' ? 'numbered-list' : 'bulleted-list')
|
.unwrapBlock(
|
||||||
|
type == 'bulleted-list' ? 'numbered-list' : 'bulleted-list'
|
||||||
|
)
|
||||||
.wrapBlock(type)
|
.wrapBlock(type)
|
||||||
} else {
|
} else {
|
||||||
change
|
change.setBlock('list-item').wrapBlock(type)
|
||||||
.setBlock('list-item')
|
|
||||||
.wrapBlock(type)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,15 +275,21 @@ class RichTextExample extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node } = props
|
const { attributes, children, node } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'block-quote': return <blockquote {...attributes}>{children}</blockquote>
|
case 'block-quote':
|
||||||
case 'bulleted-list': return <ul {...attributes}>{children}</ul>
|
return <blockquote {...attributes}>{children}</blockquote>
|
||||||
case 'heading-one': return <h1 {...attributes}>{children}</h1>
|
case 'bulleted-list':
|
||||||
case 'heading-two': return <h2 {...attributes}>{children}</h2>
|
return <ul {...attributes}>{children}</ul>
|
||||||
case 'list-item': return <li {...attributes}>{children}</li>
|
case 'heading-one':
|
||||||
case 'numbered-list': return <ol {...attributes}>{children}</ol>
|
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}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'bold': return <strong>{children}</strong>
|
case 'bold':
|
||||||
case 'code': return <code>{children}</code>
|
return <strong>{children}</strong>
|
||||||
case 'italic': return <em>{children}</em>
|
case 'code':
|
||||||
case 'underlined': return <u>{children}</u>
|
return <code>{children}</code>
|
||||||
|
case 'italic':
|
||||||
|
return <em>{children}</em>
|
||||||
|
case 'underlined':
|
||||||
|
return <u>{children}</u>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -12,7 +11,6 @@ import initialValue from './value.json'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class RTL extends React.Component {
|
class RTL extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -20,7 +18,7 @@ class RTL extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,13 +73,13 @@ class RTL extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node } = props
|
const { attributes, children, node } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'block-quote': return <blockquote {...attributes}>{children}</blockquote>
|
case 'block-quote':
|
||||||
|
return <blockquote {...attributes}>{children}</blockquote>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -12,7 +11,6 @@ import initialValue from './value.json'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class SearchHighlighting extends React.Component {
|
class SearchHighlighting extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -39,13 +37,13 @@ class SearchHighlighting extends React.Component {
|
|||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onInputChange = (event) => {
|
onInputChange = event => {
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
const string = event.target.value
|
const string = event.target.value
|
||||||
const texts = value.document.getTexts()
|
const texts = value.document.getTexts()
|
||||||
const decorations = []
|
const decorations = []
|
||||||
|
|
||||||
texts.forEach((node) => {
|
texts.forEach(node => {
|
||||||
const { key, text } = node
|
const { key, text } = node
|
||||||
const parts = text.split(string)
|
const parts = text.split(string)
|
||||||
let offset = 0
|
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
|
// to the undo/redo stack and clearing the redo stack if the user has undone
|
||||||
// changes.
|
// changes.
|
||||||
|
|
||||||
const change = value.change()
|
const change = value
|
||||||
|
.change()
|
||||||
.setOperationFlag('save', false)
|
.setOperationFlag('save', false)
|
||||||
.setValue({ decorations })
|
.setValue({ decorations })
|
||||||
.setOperationFlag('save', true)
|
.setOperationFlag('save', true)
|
||||||
@@ -140,13 +139,13 @@ class SearchHighlighting extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'highlight': return <span style={{ backgroundColor: '#ffeeba' }}>{children}</span>
|
case 'highlight':
|
||||||
|
return <span style={{ backgroundColor: '#ffeeba' }}>{children}</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -24,7 +23,6 @@ const isCodeHotkey = isKeyHotkey('mod+`')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class SyncingEditor extends React.Component {
|
class SyncingEditor extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the initial editor value.
|
* Deserialize the initial editor value.
|
||||||
*
|
*
|
||||||
@@ -42,7 +40,7 @@ class SyncingEditor extends React.Component {
|
|||||||
* @param {Array} operations
|
* @param {Array} operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
applyOperations = (operations) => {
|
applyOperations = operations => {
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
const change = value.change().applyOperations(operations)
|
const change = value.change().applyOperations(operations)
|
||||||
this.onChange(change, { remote: true })
|
this.onChange(change, { remote: true })
|
||||||
@@ -55,7 +53,7 @@ class SyncingEditor extends React.Component {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hasMark = (type) => {
|
hasMark = type => {
|
||||||
const { value } = this.state
|
const { value } = this.state
|
||||||
return value.activeMarks.some(mark => mark.type == type)
|
return value.activeMarks.some(mark => mark.type == type)
|
||||||
}
|
}
|
||||||
@@ -198,16 +196,19 @@ class SyncingEditor extends React.Component {
|
|||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'bold': return <strong>{children}</strong>
|
case 'bold':
|
||||||
case 'code': return <code>{children}</code>
|
return <strong>{children}</strong>
|
||||||
case 'italic': return <em>{children}</em>
|
case 'code':
|
||||||
case 'underlined': return <u>{children}</u>
|
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 {
|
class SyncingOperationsExample extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a reference to editor `one`.
|
* Save a reference to editor `one`.
|
||||||
*
|
*
|
||||||
* @param {SyncingEditor} one
|
* @param {SyncingEditor} one
|
||||||
*/
|
*/
|
||||||
|
|
||||||
oneRef = (one) => {
|
oneRef = one => {
|
||||||
this.one = one
|
this.one = one
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ class SyncingOperationsExample extends React.Component {
|
|||||||
* @param {SyncingEditor} two
|
* @param {SyncingEditor} two
|
||||||
*/
|
*/
|
||||||
|
|
||||||
twoRef = (two) => {
|
twoRef = two => {
|
||||||
this.two = two
|
this.two = two
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@ class SyncingOperationsExample extends React.Component {
|
|||||||
* @param {Array} operations
|
* @param {Array} operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onOneChange = (change) => {
|
onOneChange = change => {
|
||||||
const ops = change.operations
|
const ops = change.operations
|
||||||
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
|
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
|
||||||
.toJS()
|
.toJS()
|
||||||
@@ -260,7 +260,7 @@ class SyncingOperationsExample extends React.Component {
|
|||||||
* @param {Array} operations
|
* @param {Array} operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onTwoChange = (change) => {
|
onTwoChange = change => {
|
||||||
const ops = change.operations
|
const ops = change.operations
|
||||||
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
|
.filter(o => o.type != 'set_selection' && o.type != 'set_value')
|
||||||
.toJS()
|
.toJS()
|
||||||
@@ -279,10 +279,7 @@ class SyncingOperationsExample extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SyncingEditor
|
<SyncingEditor ref={this.oneRef} onChange={this.onOneChange} />
|
||||||
ref={this.oneRef}
|
|
||||||
onChange={this.onOneChange}
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: '20px',
|
height: '20px',
|
||||||
@@ -290,14 +287,10 @@ class SyncingOperationsExample extends React.Component {
|
|||||||
margin: '20px -20px',
|
margin: '20px -20px',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SyncingEditor
|
<SyncingEditor ref={this.twoRef} onChange={this.onTwoChange} />
|
||||||
ref={this.twoRef}
|
|
||||||
onChange={this.onTwoChange}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Editor } from 'slate-react'
|
import { Editor } from 'slate-react'
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
|
|
||||||
@@ -12,7 +11,6 @@ import initialValue from './value.json'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Tables extends React.Component {
|
class Tables extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize the raw initial value.
|
* Deserialize the raw initial value.
|
||||||
*
|
*
|
||||||
@@ -20,7 +18,7 @@ class Tables extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
value: Value.fromJSON(initialValue)
|
value: Value.fromJSON(initialValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,9 +99,12 @@ class Tables extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'Backspace': return this.onBackspace(event, change)
|
case 'Backspace':
|
||||||
case 'Delete': return this.onDelete(event, change)
|
return this.onBackspace(event, change)
|
||||||
case 'Enter': return this.onEnter(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}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderNode = (props) => {
|
renderNode = props => {
|
||||||
const { attributes, children, node } = props
|
const { attributes, children, node } = props
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'table': return <table><tbody {...attributes}>{children}</tbody></table>
|
case 'table':
|
||||||
case 'table-row': return <tr {...attributes}>{children}</tr>
|
return (
|
||||||
case 'table-cell': return <td {...attributes}>{children}</td>
|
<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}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
renderMark = (props) => {
|
renderMark = props => {
|
||||||
const { children, mark } = props
|
const { children, mark } = props
|
||||||
switch (mark.type) {
|
switch (mark.type) {
|
||||||
case 'bold': return <strong>{children}</strong>
|
case 'bold':
|
||||||
|
return <strong>{children}</strong>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
11
package.json
11
package.json
@@ -19,7 +19,9 @@
|
|||||||
"cross-env": "^5.1.3",
|
"cross-env": "^5.1.3",
|
||||||
"disc": "^1.3.2",
|
"disc": "^1.3.2",
|
||||||
"eslint": "^4.16.0",
|
"eslint": "^4.16.0",
|
||||||
|
"eslint-config-prettier": "^2.9.0",
|
||||||
"eslint-plugin-import": "^2.8.0",
|
"eslint-plugin-import": "^2.8.0",
|
||||||
|
"eslint-plugin-prettier": "^2.5.0",
|
||||||
"eslint-plugin-react": "^7.6.0",
|
"eslint-plugin-react": "^7.6.0",
|
||||||
"faker": "^3.1.0",
|
"faker": "^3.1.0",
|
||||||
"fbjs": "^0.8.3",
|
"fbjs": "^0.8.3",
|
||||||
@@ -36,6 +38,7 @@
|
|||||||
"matcha": "^0.7.0",
|
"matcha": "^0.7.0",
|
||||||
"mocha": "^2.5.3",
|
"mocha": "^2.5.3",
|
||||||
"npm-run-all": "^4.1.1",
|
"npm-run-all": "^4.1.1",
|
||||||
|
"prettier": "^1.10.2",
|
||||||
"prismjs": "^1.5.1",
|
"prismjs": "^1.5.1",
|
||||||
"react": "^16.0.0",
|
"react": "^16.0.0",
|
||||||
"react-dom": "^16.0.0",
|
"react-dom": "^16.0.0",
|
||||||
@@ -77,13 +80,19 @@
|
|||||||
"build": "cross-env NODE_ENV=production rollup --config",
|
"build": "cross-env NODE_ENV=production rollup --config",
|
||||||
"clean": "lerna run clean && rm -rf ./node_modules ./dist ./examples/build.*.js",
|
"clean": "lerna run clean && rm -rf ./node_modules ./dist ./examples/build.*.js",
|
||||||
"gh-pages": "yarn build && gh-pages --dist ./examples",
|
"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",
|
"open": "open http://localhost:8080/dev.html",
|
||||||
|
"prettier": "prettier --write '**/*.{js,jsx}'",
|
||||||
"release": "yarn test && yarn lint && lerna publish && yarn gh-pages",
|
"release": "yarn test && yarn lint && lerna publish && yarn gh-pages",
|
||||||
"server": "http-server ./examples",
|
"server": "http-server ./examples",
|
||||||
"start": "npm-run-all --parallel --print-label watch server",
|
"start": "npm-run-all --parallel --print-label watch server",
|
||||||
"test": "cross-env BABEL_ENV=test mocha --require babel-core/register ./packages/*/test/index.js",
|
"test": "cross-env BABEL_ENV=test mocha --require babel-core/register ./packages/*/test/index.js",
|
||||||
"watch": "rollup --config --watch",
|
"watch": "rollup --config --watch",
|
||||||
"watch:packages": "cross-env SKIP_EXAMPLES=true yarn watch"
|
"watch:packages": "cross-env SKIP_EXAMPLES=true yarn watch"
|
||||||
|
},
|
||||||
|
"prettier": {
|
||||||
|
"singleQuote": true,
|
||||||
|
"semi": false,
|
||||||
|
"trailingComma": "es5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Value } from 'slate'
|
import { Value } from 'slate'
|
||||||
import { atob, btoa } from 'isomorphic-base64'
|
import { atob, btoa } from 'isomorphic-base64'
|
||||||
|
|
||||||
@@ -91,5 +90,5 @@ export default {
|
|||||||
deserialize,
|
deserialize,
|
||||||
deserializeNode,
|
deserializeNode,
|
||||||
serialize,
|
serialize,
|
||||||
serializeNode
|
serializeNode,
|
||||||
}
|
}
|
||||||
|
@@ -6,11 +6,10 @@
|
|||||||
* @type {Boolean}
|
* @type {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const IS_DEV = (
|
const IS_DEV =
|
||||||
typeof process !== 'undefined' &&
|
typeof process !== 'undefined' &&
|
||||||
process.env &&
|
process.env &&
|
||||||
process.env.NODE_ENV !== 'production'
|
process.env.NODE_ENV !== 'production'
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Has console?
|
* Has console?
|
||||||
@@ -18,12 +17,11 @@ const IS_DEV = (
|
|||||||
* @type {Boolean}
|
* @type {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const HAS_CONSOLE = (
|
const HAS_CONSOLE =
|
||||||
typeof console != 'undefined' &&
|
typeof console != 'undefined' &&
|
||||||
typeof console.log == 'function' &&
|
typeof console.log == 'function' &&
|
||||||
typeof console.warn == 'function' &&
|
typeof console.warn == 'function' &&
|
||||||
typeof console.error == 'function'
|
typeof console.error == 'function'
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a `message` at `level`.
|
* Log a `message` at `level`.
|
||||||
@@ -50,7 +48,6 @@ function log(level, message, ...args) {
|
|||||||
* @param {Any} ...args
|
* @param {Any} ...args
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
function error(message, ...args) {
|
function error(message, ...args) {
|
||||||
if (HAS_CONSOLE) {
|
if (HAS_CONSOLE) {
|
||||||
console.error(message, ...args)
|
console.error(message, ...args)
|
||||||
|
@@ -13,20 +13,24 @@ const html = new Html({
|
|||||||
switch (obj.object) {
|
switch (obj.object) {
|
||||||
case 'block': {
|
case 'block': {
|
||||||
switch (obj.type) {
|
switch (obj.type) {
|
||||||
case 'paragraph': return React.createElement('p', {}, children)
|
case 'paragraph':
|
||||||
case 'quote': return React.createElement('blockquote', {}, children)
|
return React.createElement('p', {}, children)
|
||||||
|
case 'quote':
|
||||||
|
return React.createElement('blockquote', {}, children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'mark': {
|
case 'mark': {
|
||||||
switch (obj.type) {
|
switch (obj.type) {
|
||||||
case 'bold': return React.createElement('strong', {}, children)
|
case 'bold':
|
||||||
case 'italic': return React.createElement('em', {}, children)
|
return React.createElement('strong', {}, children)
|
||||||
|
case 'italic':
|
||||||
|
return React.createElement('em', {}, children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function(string) {
|
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!
|
This is editable <strong>rich</strong> text, <em>much</em> better than a textarea!
|
||||||
</p>
|
</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
`.trim().repeat(10)
|
`
|
||||||
|
.trim()
|
||||||
|
.repeat(10)
|
||||||
|
@@ -14,20 +14,24 @@ const html = new Html({
|
|||||||
switch (obj.object) {
|
switch (obj.object) {
|
||||||
case 'block': {
|
case 'block': {
|
||||||
switch (obj.type) {
|
switch (obj.type) {
|
||||||
case 'paragraph': return React.createElement('p', {}, children)
|
case 'paragraph':
|
||||||
case 'quote': return React.createElement('blockquote', {}, children)
|
return React.createElement('p', {}, children)
|
||||||
|
case 'quote':
|
||||||
|
return React.createElement('blockquote', {}, children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'mark': {
|
case 'mark': {
|
||||||
switch (obj.type) {
|
switch (obj.type) {
|
||||||
case 'bold': return React.createElement('strong', {}, children)
|
case 'bold':
|
||||||
case 'italic': return React.createElement('em', {}, children)
|
return React.createElement('strong', {}, children)
|
||||||
|
case 'italic':
|
||||||
|
return React.createElement('em', {}, children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function(state) {
|
export default function(state) {
|
||||||
@@ -40,7 +44,8 @@ export const input = (
|
|||||||
{Array.from(Array(10)).map(() => (
|
{Array.from(Array(10)).map(() => (
|
||||||
<quote>
|
<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>
|
</quote>
|
||||||
))}
|
))}
|
||||||
|
@@ -9,9 +9,11 @@ import { __clear } from '../../slate/lib/utils/memoize'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const categoryDir = resolve(__dirname)
|
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, () => {
|
suite(category, () => {
|
||||||
set('iterations', 50)
|
set('iterations', 50)
|
||||||
set('mintime', 1000)
|
set('mintime', 1000)
|
||||||
@@ -23,9 +25,12 @@ categories.forEach((category) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const benchmarkDir = resolve(categoryDir, 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 dir = resolve(benchmarkDir, benchmark)
|
||||||
const module = require(dir)
|
const module = require(dir)
|
||||||
const fn = module.default
|
const fn = module.default
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { renderToStaticMarkup } from 'react-dom/server'
|
import { renderToStaticMarkup } from 'react-dom/server'
|
||||||
import typeOf from 'type-of'
|
import typeOf from 'type-of'
|
||||||
@@ -13,7 +12,7 @@ import { Record } from 'immutable'
|
|||||||
|
|
||||||
const String = new Record({
|
const String = new Record({
|
||||||
object: 'string',
|
object: 'string',
|
||||||
text: ''
|
text: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,15 +23,16 @@ const String = new Record({
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const TEXT_RULE = {
|
const TEXT_RULE = {
|
||||||
|
|
||||||
deserialize(el) {
|
deserialize(el) {
|
||||||
if (el.tagName && el.tagName.toLowerCase() === 'br') {
|
if (el.tagName && el.tagName.toLowerCase() === 'br') {
|
||||||
return {
|
return {
|
||||||
object: 'text',
|
object: 'text',
|
||||||
leaves: [{
|
leaves: [
|
||||||
|
{
|
||||||
object: 'leaf',
|
object: 'leaf',
|
||||||
text: '\n'
|
text: '\n',
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,26 +41,25 @@ const TEXT_RULE = {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
object: 'text',
|
object: 'text',
|
||||||
leaves: [{
|
leaves: [
|
||||||
|
{
|
||||||
object: 'leaf',
|
object: 'leaf',
|
||||||
text: el.nodeValue
|
text: el.nodeValue,
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
serialize(obj, children) {
|
serialize(obj, children) {
|
||||||
if (obj.object === 'string') {
|
if (obj.object === 'string') {
|
||||||
return children
|
return children.split('\n').reduce((array, text, i) => {
|
||||||
.split('\n')
|
|
||||||
.reduce((array, text, i) => {
|
|
||||||
if (i != 0) array.push(<br />)
|
if (i != 0) array.push(<br />)
|
||||||
array.push(text)
|
array.push(text)
|
||||||
return array
|
return array
|
||||||
}, [])
|
}, [])
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,7 +71,9 @@ const TEXT_RULE = {
|
|||||||
|
|
||||||
function defaultParseHtml(html) {
|
function defaultParseHtml(html) {
|
||||||
if (typeof DOMParser === 'undefined') {
|
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')
|
const parsed = new DOMParser().parseFromString(html, 'text/html')
|
||||||
@@ -87,7 +88,6 @@ function defaultParseHtml(html) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Html {
|
class Html {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new serializer with `rules`.
|
* Create a new serializer with `rules`.
|
||||||
*
|
*
|
||||||
@@ -154,7 +154,8 @@ class Html {
|
|||||||
|
|
||||||
// TODO: pretty sure this is no longer needed.
|
// TODO: pretty sure this is no longer needed.
|
||||||
if (nodes.length == 0) {
|
if (nodes.length == 0) {
|
||||||
nodes = [{
|
nodes = [
|
||||||
|
{
|
||||||
object: 'block',
|
object: 'block',
|
||||||
data: {},
|
data: {},
|
||||||
isVoid: false,
|
isVoid: false,
|
||||||
@@ -167,11 +168,12 @@ class Html {
|
|||||||
object: 'leaf',
|
object: 'leaf',
|
||||||
text: '',
|
text: '',
|
||||||
marks: [],
|
marks: [],
|
||||||
}
|
},
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = {
|
const json = {
|
||||||
@@ -180,7 +182,7 @@ class Html {
|
|||||||
object: 'document',
|
object: 'document',
|
||||||
data: {},
|
data: {},
|
||||||
nodes,
|
nodes,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret = toJSON ? json : Value.fromJSON(json)
|
const ret = toJSON ? json : Value.fromJSON(json)
|
||||||
@@ -197,7 +199,7 @@ class Html {
|
|||||||
deserializeElements = (elements = []) => {
|
deserializeElements = (elements = []) => {
|
||||||
let nodes = []
|
let nodes = []
|
||||||
|
|
||||||
elements.filter(this.cruftNewline).forEach((element) => {
|
elements.filter(this.cruftNewline).forEach(element => {
|
||||||
const node = this.deserializeElement(element)
|
const node = this.deserializeElement(element)
|
||||||
switch (typeOf(node)) {
|
switch (typeOf(node)) {
|
||||||
case 'array':
|
case 'array':
|
||||||
@@ -219,14 +221,14 @@ class Html {
|
|||||||
* @return {Any}
|
* @return {Any}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
deserializeElement = (element) => {
|
deserializeElement = element => {
|
||||||
let node
|
let node
|
||||||
|
|
||||||
if (!element.tagName) {
|
if (!element.tagName) {
|
||||||
element.tagName = ''
|
element.tagName = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const next = (elements) => {
|
const next = elements => {
|
||||||
if (Object.prototype.toString.call(elements) == '[object NodeList]') {
|
if (Object.prototype.toString.call(elements) == '[object NodeList]') {
|
||||||
elements = Array.from(elements)
|
elements = Array.from(elements)
|
||||||
}
|
}
|
||||||
@@ -240,7 +242,9 @@ class Html {
|
|||||||
case 'undefined':
|
case 'undefined':
|
||||||
return
|
return
|
||||||
default:
|
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 ret = rule.deserialize(element, next)
|
||||||
const type = typeOf(ret)
|
const type = typeOf(ret)
|
||||||
|
|
||||||
if (type != 'array' && type != 'object' && type != 'null' && type != 'undefined') {
|
if (
|
||||||
throw new Error(`A rule returned an invalid deserialized representation: "${node}".`)
|
type != 'array' &&
|
||||||
|
type != 'object' &&
|
||||||
|
type != 'null' &&
|
||||||
|
type != 'undefined'
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`A rule returned an invalid deserialized representation: "${node}".`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret === undefined) {
|
if (ret === undefined) {
|
||||||
@@ -276,23 +287,19 @@ class Html {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
deserializeMark = (mark) => {
|
deserializeMark = mark => {
|
||||||
const { type, data } = mark
|
const { type, data } = mark
|
||||||
|
|
||||||
const applyMark = (node) => {
|
const applyMark = node => {
|
||||||
if (node.object == 'mark') {
|
if (node.object == 'mark') {
|
||||||
return this.deserializeMark(node)
|
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 = leaf.marks || []
|
||||||
leaf.marks.push({ type, data })
|
leaf.marks.push({ type, data })
|
||||||
return leaf
|
return leaf
|
||||||
})
|
})
|
||||||
}
|
} else {
|
||||||
|
|
||||||
else {
|
|
||||||
node.nodes = node.nodes.map(applyMark)
|
node.nodes = node.nodes.map(applyMark)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +340,7 @@ class Html {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
serializeNode = (node) => {
|
serializeNode = node => {
|
||||||
if (node.object === 'text') {
|
if (node.object === 'text') {
|
||||||
const leaves = node.getLeaves()
|
const leaves = node.getLeaves()
|
||||||
return leaves.map(this.serializeLeaf)
|
return leaves.map(this.serializeLeaf)
|
||||||
@@ -357,7 +364,7 @@ class Html {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
serializeLeaf = (leaf) => {
|
serializeLeaf = leaf => {
|
||||||
const string = new String({ text: leaf.text })
|
const string = new String({ text: leaf.text })
|
||||||
const text = this.serializeString(string)
|
const text = this.serializeString(string)
|
||||||
|
|
||||||
@@ -379,7 +386,7 @@ class Html {
|
|||||||
* @return {String}
|
* @return {String}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
serializeString = (string) => {
|
serializeString = string => {
|
||||||
for (const rule of this.rules) {
|
for (const rule of this.rules) {
|
||||||
if (!rule.serialize) continue
|
if (!rule.serialize) continue
|
||||||
const ret = rule.serialize(string, string.text)
|
const ret = rule.serialize(string, string.text)
|
||||||
@@ -394,10 +401,9 @@ class Html {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cruftNewline = (element) => {
|
cruftNewline = element => {
|
||||||
return !(element.nodeName === '#text' && element.nodeValue == '\n')
|
return !(element.nodeName === '#text' && element.nodeValue == '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -23,9 +22,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -36,9 +35,7 @@ export const output = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -16,9 +15,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -17,9 +16,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -29,9 +28,7 @@ export const input = `
|
|||||||
export const output = (
|
export const output = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph thing="value">
|
<paragraph thing="value">one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -16,9 +15,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -16,9 +15,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -28,9 +27,7 @@ export const input = `
|
|||||||
export const output = (
|
export const output = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -16,15 +15,15 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
defaultBlock: {
|
defaultBlock: {
|
||||||
type: 'default',
|
type: 'default',
|
||||||
data: {
|
data: {
|
||||||
thing: 'value'
|
thing: 'value',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -35,9 +34,7 @@ export const input = `
|
|||||||
export const output = (
|
export const output = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
<block type="default" data={{ thing: 'value' }}>
|
<block type="default" data={{ thing: 'value' }}>
|
||||||
two
|
two
|
||||||
</block>
|
</block>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -16,9 +15,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -29,9 +28,7 @@ export const input = `
|
|||||||
export const output = (
|
export const output = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -30,9 +29,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -44,9 +43,7 @@ export const output = (
|
|||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>
|
||||||
<hashtag>
|
<hashtag>one</hashtag>
|
||||||
one
|
|
||||||
</hashtag>
|
|
||||||
</link>
|
</link>
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -23,9 +22,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -24,9 +23,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -37,9 +36,7 @@ export const output = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link thing="value">
|
<link thing="value">one</link>
|
||||||
one
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -24,9 +23,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -23,9 +22,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -36,9 +35,7 @@ export const output = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>one</link>
|
||||||
one
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -30,9 +29,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -30,9 +29,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -43,7 +42,9 @@ export const output = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
o<i>n<b>e</b></i>
|
o<i>
|
||||||
|
n<b>e</b>
|
||||||
|
</i>
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -24,9 +23,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -23,9 +22,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -11,7 +10,7 @@ export const config = {
|
|||||||
object: 'block',
|
object: 'block',
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deserialize(el, next) {
|
deserialize(el, next) {
|
||||||
@@ -19,9 +18,9 @@ export const config = {
|
|||||||
object: 'block',
|
object: 'block',
|
||||||
type: 'quote',
|
type: 'quote',
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -16,9 +15,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import h from '../helpers/h'
|
import h from '../helpers/h'
|
||||||
@@ -26,9 +25,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
@@ -12,9 +11,9 @@ export const config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
@@ -37,13 +36,13 @@ export const output = {
|
|||||||
{
|
{
|
||||||
object: 'leaf',
|
object: 'leaf',
|
||||||
text: 'one',
|
text: 'one',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const options = {
|
export const options = {
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { createHyperscript } from 'slate-hyperscript'
|
import { createHyperscript } from 'slate-hyperscript'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,7 +15,7 @@ const h = createHyperscript({
|
|||||||
image: {
|
image: {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
isVoid: true,
|
isVoid: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
inlines: {
|
inlines: {
|
||||||
link: 'link',
|
link: 'link',
|
||||||
@@ -25,7 +24,7 @@ const h = createHyperscript({
|
|||||||
emoji: {
|
emoji: {
|
||||||
type: 'emoji',
|
type: 'emoji',
|
||||||
isVoid: true,
|
isVoid: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
marks: {
|
marks: {
|
||||||
b: 'bold',
|
b: 'bold',
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Dependencies.
|
* Dependencies.
|
||||||
*/
|
*/
|
||||||
@@ -25,7 +24,10 @@ beforeEach(() => {
|
|||||||
describe('slate-html-serializer', () => {
|
describe('slate-html-serializer', () => {
|
||||||
describe('deserialize()', () => {
|
describe('deserialize()', () => {
|
||||||
const dir = resolve(__dirname, './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) {
|
for (const test of tests) {
|
||||||
it(test, async () => {
|
it(test, async () => {
|
||||||
@@ -42,7 +44,10 @@ describe('slate-html-serializer', () => {
|
|||||||
|
|
||||||
describe('serialize()', () => {
|
describe('serialize()', () => {
|
||||||
const dir = resolve(__dirname, './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) {
|
for (const test of tests) {
|
||||||
it(test, async () => {
|
it(test, async () => {
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -9,20 +8,20 @@ export const rules = [
|
|||||||
serialize(obj, children) {
|
serialize(obj, children) {
|
||||||
if (obj.object != 'block') return
|
if (obj.object != 'block') return
|
||||||
switch (obj.type) {
|
switch (obj.type) {
|
||||||
case 'paragraph': return React.createElement('p', {}, children)
|
case 'paragraph':
|
||||||
case 'quote': return React.createElement('blockquote', {}, children)
|
return React.createElement('p', {}, children)
|
||||||
}
|
case 'quote':
|
||||||
}
|
return React.createElement('blockquote', {}, children)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -8,18 +7,20 @@ export const rules = [
|
|||||||
{
|
{
|
||||||
serialize(obj, children) {
|
serialize(obj, children) {
|
||||||
if (obj.object == 'block' && obj.type == 'paragraph') {
|
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 = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph thing="value">
|
<paragraph thing="value">one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -10,8 +9,8 @@ export const rules = [
|
|||||||
if (obj.object == 'block' && obj.type == 'image') {
|
if (obj.object == 'block' && obj.type == 'image') {
|
||||||
return React.createElement('img')
|
return React.createElement('img')
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -14,8 +13,8 @@ export const rules = [
|
|||||||
if (obj.object == 'mark' && obj.type == 'bold') {
|
if (obj.object == 'mark' && obj.type == 'bold') {
|
||||||
return React.createElement('strong', {}, children)
|
return React.createElement('strong', {}, children)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -10,16 +9,14 @@ export const rules = [
|
|||||||
if (obj.object == 'block' && obj.type == 'paragraph') {
|
if (obj.object == 'block' && obj.type == 'paragraph') {
|
||||||
return React.createElement('p', {}, children)
|
return React.createElement('p', {}, children)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -18,8 +17,8 @@ export const rules = [
|
|||||||
if (obj.object == 'inline' && obj.type == 'hashtag') {
|
if (obj.object == 'inline' && obj.type == 'hashtag') {
|
||||||
return React.createElement('span', {}, children)
|
return React.createElement('span', {}, children)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
@@ -27,9 +26,7 @@ export const input = (
|
|||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>
|
||||||
<hashtag>
|
<hashtag>one</hashtag>
|
||||||
one
|
|
||||||
</hashtag>
|
|
||||||
</link>
|
</link>
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -12,19 +11,21 @@ export const rules = [
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (obj.object == 'inline' && obj.type == 'link') {
|
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 = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link href="https://google.com">
|
<link href="https://google.com">one</link>
|
||||||
one
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -14,8 +13,8 @@ export const rules = [
|
|||||||
if (obj.object == 'inline' && obj.type == 'emoji') {
|
if (obj.object == 'inline' && obj.type == 'emoji') {
|
||||||
return React.createElement('img')
|
return React.createElement('img')
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -18,8 +17,8 @@ export const rules = [
|
|||||||
if (obj.object == 'mark' && obj.type == 'bold') {
|
if (obj.object == 'mark' && obj.type == 'bold') {
|
||||||
return React.createElement('strong', {}, children)
|
return React.createElement('strong', {}, children)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -14,17 +13,15 @@ export const rules = [
|
|||||||
if (obj.object == 'inline' && obj.type == 'link') {
|
if (obj.object == 'inline' && obj.type == 'link') {
|
||||||
return React.createElement('a', {}, children)
|
return React.createElement('a', {}, children)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>one</link>
|
||||||
one
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/** @jsx h */
|
/** @jsx h */
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -7,23 +6,21 @@ import h from '../helpers/h'
|
|||||||
export const rules = [
|
export const rules = [
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
serialize(obj, children) {}
|
serialize(obj, children) {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
serialize(obj, children) {
|
serialize(obj, children) {
|
||||||
if (obj.object == 'block' && obj.type == 'paragraph') {
|
if (obj.object == 'block' && obj.type == 'paragraph') {
|
||||||
return React.createElement('p', {}, children)
|
return React.createElement('p', {}, children)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -1,17 +1,7 @@
|
|||||||
|
|
||||||
import isEmpty from 'is-empty'
|
import isEmpty from 'is-empty'
|
||||||
import isPlainObject from 'is-plain-object'
|
import isPlainObject from 'is-plain-object'
|
||||||
|
|
||||||
import {
|
import { Block, Document, Inline, Mark, Node, Range, Text, Value } from 'slate'
|
||||||
Block,
|
|
||||||
Document,
|
|
||||||
Inline,
|
|
||||||
Mark,
|
|
||||||
Node,
|
|
||||||
Range,
|
|
||||||
Text,
|
|
||||||
Value,
|
|
||||||
} from 'slate'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create selection point constants, for comparison by reference.
|
* Create selection point constants, for comparison by reference.
|
||||||
@@ -30,7 +20,6 @@ const FOCUS = {}
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const CREATORS = {
|
const CREATORS = {
|
||||||
|
|
||||||
anchor(tagName, attributes, children) {
|
anchor(tagName, attributes, children) {
|
||||||
return ANCHOR
|
return ANCHOR
|
||||||
},
|
},
|
||||||
@@ -83,7 +72,7 @@ const CREATORS = {
|
|||||||
// Search the document's texts to see if any of them have the anchor or
|
// Search the document's texts to see if any of them have the anchor or
|
||||||
// focus information saved, so we can set the selection.
|
// focus information saved, so we can set the selection.
|
||||||
if (document) {
|
if (document) {
|
||||||
document.getTexts().forEach((text) => {
|
document.getTexts().forEach(text => {
|
||||||
if (text.__anchor != null) {
|
if (text.__anchor != null) {
|
||||||
props.anchorKey = text.key
|
props.anchorKey = text.key
|
||||||
props.anchorOffset = text.__anchor
|
props.anchorOffset = text.__anchor
|
||||||
@@ -99,11 +88,15 @@ const CREATORS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (props.anchorKey && !props.focusKey) {
|
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) {
|
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)) {
|
if (!isEmpty(props)) {
|
||||||
@@ -118,7 +111,6 @@ const CREATORS = {
|
|||||||
const nodes = createChildren(children, { key: attributes.key })
|
const nodes = createChildren(children, { key: attributes.key })
|
||||||
return nodes
|
return nodes
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -184,11 +176,12 @@ function createChildren(children, options = {}) {
|
|||||||
node = next
|
node = next
|
||||||
}
|
}
|
||||||
|
|
||||||
children.forEach((child) => {
|
children.forEach(child => {
|
||||||
// If the child is a non-text node, push the current node and the new 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.
|
// onto the array, then creating a new node for future selection tracking.
|
||||||
if (Node.isNode(child) && !Text.isText(child)) {
|
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)
|
array.push(child)
|
||||||
node = Text.create()
|
node = Text.create()
|
||||||
length = 0
|
length = 0
|
||||||
@@ -211,7 +204,7 @@ function createChildren(children, options = {}) {
|
|||||||
setNode(node.set('key', child.key))
|
setNode(node.set('key', child.key))
|
||||||
}
|
}
|
||||||
|
|
||||||
child.getLeaves().forEach((leaf) => {
|
child.getLeaves().forEach(leaf => {
|
||||||
let { marks } = leaf
|
let { marks } = leaf
|
||||||
if (options.marks) marks = marks.union(options.marks)
|
if (options.marks) marks = marks.union(options.marks)
|
||||||
setNode(node.insertText(i, leaf.text, marks))
|
setNode(node.insertText(i, leaf.text, marks))
|
||||||
@@ -243,26 +236,22 @@ function createChildren(children, options = {}) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function resolveCreators(options) {
|
function resolveCreators(options) {
|
||||||
const {
|
const { blocks = {}, inlines = {}, marks = {} } = options
|
||||||
blocks = {},
|
|
||||||
inlines = {},
|
|
||||||
marks = {},
|
|
||||||
} = options
|
|
||||||
|
|
||||||
const creators = {
|
const creators = {
|
||||||
...CREATORS,
|
...CREATORS,
|
||||||
...(options.creators || {}),
|
...(options.creators || {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(blocks).map((key) => {
|
Object.keys(blocks).map(key => {
|
||||||
creators[key] = normalizeNode(key, blocks[key], 'block')
|
creators[key] = normalizeNode(key, blocks[key], 'block')
|
||||||
})
|
})
|
||||||
|
|
||||||
Object.keys(inlines).map((key) => {
|
Object.keys(inlines).map(key => {
|
||||||
creators[key] = normalizeNode(key, inlines[key], 'inline')
|
creators[key] = normalizeNode(key, inlines[key], 'inline')
|
||||||
})
|
})
|
||||||
|
|
||||||
Object.keys(marks).map((key) => {
|
Object.keys(marks).map(key => {
|
||||||
creators[key] = normalizeMark(key, marks[key])
|
creators[key] = normalizeMark(key, marks[key])
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -297,14 +286,16 @@ function normalizeNode(key, value, object) {
|
|||||||
data: {
|
data: {
|
||||||
...(value.data || {}),
|
...(value.data || {}),
|
||||||
...rest,
|
...rest,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return CREATORS[object](tagName, attrs, children)
|
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: {
|
data: {
|
||||||
...(value.data || {}),
|
...(value.data || {}),
|
||||||
...attributes,
|
...attributes,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return CREATORS.mark(tagName, attrs, children)
|
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}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -9,9 +9,11 @@ import { __clear } from '../../slate/lib/utils/memoize'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const categoryDir = resolve(__dirname)
|
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, () => {
|
suite(category, () => {
|
||||||
set('iterations', 50)
|
set('iterations', 50)
|
||||||
set('mintime', 1000)
|
set('mintime', 1000)
|
||||||
@@ -23,9 +25,12 @@ categories.forEach((category) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const benchmarkDir = resolve(categoryDir, 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 dir = resolve(benchmarkDir, benchmark)
|
||||||
const module = require(dir)
|
const module = require(dir)
|
||||||
const fn = module.default
|
const fn = module.default
|
||||||
|
@@ -9,4 +9,6 @@ export default function (string) {
|
|||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
This is editable plain text, just like a text area.
|
This is editable plain text, just like a text area.
|
||||||
`.trim().repeat(10)
|
`
|
||||||
|
.trim()
|
||||||
|
.repeat(10)
|
||||||
|
@@ -15,7 +15,8 @@ export const input = (
|
|||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<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>
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</quote>
|
</quote>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { Block, Mark, Node, Value } from 'slate'
|
import { Block, Mark, Node, Value } from 'slate'
|
||||||
import { Set } from 'immutable'
|
import { Set } from 'immutable'
|
||||||
|
|
||||||
@@ -14,11 +13,7 @@ import { Set } from 'immutable'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function deserialize(string, options = {}) {
|
function deserialize(string, options = {}) {
|
||||||
let {
|
let { defaultBlock = 'line', defaultMarks = [], toJSON = false } = options
|
||||||
defaultBlock = 'line',
|
|
||||||
defaultMarks = [],
|
|
||||||
toJSON = false,
|
|
||||||
} = options
|
|
||||||
|
|
||||||
if (Set.isSet(defaultMarks)) {
|
if (Set.isSet(defaultMarks)) {
|
||||||
defaultMarks = defaultMarks.toArray()
|
defaultMarks = defaultMarks.toArray()
|
||||||
@@ -32,7 +27,7 @@ function deserialize(string, options = {}) {
|
|||||||
document: {
|
document: {
|
||||||
object: 'document',
|
object: 'document',
|
||||||
data: {},
|
data: {},
|
||||||
nodes: string.split('\n').map((line) => {
|
nodes: string.split('\n').map(line => {
|
||||||
return {
|
return {
|
||||||
...defaultBlock,
|
...defaultBlock,
|
||||||
object: 'block',
|
object: 'block',
|
||||||
@@ -46,13 +41,13 @@ function deserialize(string, options = {}) {
|
|||||||
object: 'leaf',
|
object: 'leaf',
|
||||||
text: line,
|
text: line,
|
||||||
marks: defaultMarks,
|
marks: defaultMarks,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret = toJSON ? json : Value.fromJSON(json)
|
const ret = toJSON ? json : Value.fromJSON(json)
|
||||||
@@ -79,7 +74,7 @@ function serialize(value) {
|
|||||||
|
|
||||||
function serializeNode(node) {
|
function serializeNode(node) {
|
||||||
if (
|
if (
|
||||||
(node.object == 'document') ||
|
node.object == 'document' ||
|
||||||
(node.object == 'block' && Block.isBlockList(node.nodes))
|
(node.object == 'block' && Block.isBlockList(node.nodes))
|
||||||
) {
|
) {
|
||||||
return node.nodes.map(serializeNode).join('\n')
|
return node.nodes.map(serializeNode).join('\n')
|
||||||
@@ -96,5 +91,5 @@ function serializeNode(node) {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
deserialize,
|
deserialize,
|
||||||
serialize
|
serialize,
|
||||||
}
|
}
|
||||||
|
@@ -10,12 +10,8 @@ two
|
|||||||
export const output = (
|
export const output = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<line>
|
<line>one</line>
|
||||||
one
|
<line>two</line>
|
||||||
</line>
|
|
||||||
<line>
|
|
||||||
two
|
|
||||||
</line>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -9,9 +9,7 @@ one
|
|||||||
export const output = (
|
export const output = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<line>
|
<line>one</line>
|
||||||
one
|
|
||||||
</line>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export const input = `
|
export const input = `
|
||||||
one
|
one
|
||||||
`.trim()
|
`.trim()
|
||||||
@@ -22,15 +21,15 @@ export const output = {
|
|||||||
object: 'leaf',
|
object: 'leaf',
|
||||||
text: 'one',
|
text: 'one',
|
||||||
marks: [],
|
marks: [],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const options = {
|
export const options = {
|
||||||
toJSON: true
|
toJSON: true,
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { createHyperscript } from 'slate-hyperscript'
|
import { createHyperscript } from 'slate-hyperscript'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,7 +15,7 @@ const h = createHyperscript({
|
|||||||
image: {
|
image: {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
isVoid: true,
|
isVoid: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
inlines: {
|
inlines: {
|
||||||
link: 'link',
|
link: 'link',
|
||||||
@@ -25,7 +24,7 @@ const h = createHyperscript({
|
|||||||
emoji: {
|
emoji: {
|
||||||
type: 'emoji',
|
type: 'emoji',
|
||||||
isVoid: true,
|
isVoid: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
marks: {
|
marks: {
|
||||||
b: 'bold',
|
b: 'bold',
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Dependencies.
|
* Dependencies.
|
||||||
*/
|
*/
|
||||||
@@ -24,7 +23,10 @@ beforeEach(() => {
|
|||||||
describe('slate-plain-serializer', () => {
|
describe('slate-plain-serializer', () => {
|
||||||
describe('deserialize()', () => {
|
describe('deserialize()', () => {
|
||||||
const dir = resolve(__dirname, './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) {
|
for (const test of tests) {
|
||||||
it(test, async () => {
|
it(test, async () => {
|
||||||
@@ -40,7 +42,10 @@ describe('slate-plain-serializer', () => {
|
|||||||
|
|
||||||
describe('serialize()', () => {
|
describe('serialize()', () => {
|
||||||
const dir = resolve(__dirname, './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) {
|
for (const test of tests) {
|
||||||
it(test, async () => {
|
it(test, async () => {
|
||||||
|
@@ -5,13 +5,9 @@ import h from '../helpers/h'
|
|||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
<paragraph />
|
<paragraph />
|
||||||
<paragraph>
|
<paragraph>three</paragraph>
|
||||||
three
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -5,15 +5,9 @@ import h from '../helpers/h'
|
|||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
<paragraph>two</paragraph>
|
||||||
</paragraph>
|
<paragraph>three</paragraph>
|
||||||
<paragraph>
|
|
||||||
two
|
|
||||||
</paragraph>
|
|
||||||
<paragraph>
|
|
||||||
three
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -6,18 +6,12 @@ export const input = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
<paragraph>two</paragraph>
|
||||||
</paragraph>
|
|
||||||
<paragraph>
|
|
||||||
two
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph />
|
<paragraph />
|
||||||
<paragraph>
|
<paragraph>four</paragraph>
|
||||||
four
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -6,20 +6,12 @@ export const input = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
<paragraph>two</paragraph>
|
||||||
</paragraph>
|
|
||||||
<paragraph>
|
|
||||||
two
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>three</paragraph>
|
||||||
three
|
<paragraph>four</paragraph>
|
||||||
</paragraph>
|
|
||||||
<paragraph>
|
|
||||||
four
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -7,20 +7,12 @@ export const input = (
|
|||||||
<document>
|
<document>
|
||||||
<quote>
|
<quote>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
<paragraph>two</paragraph>
|
||||||
</paragraph>
|
|
||||||
<paragraph>
|
|
||||||
two
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>three</paragraph>
|
||||||
three
|
<paragraph>four</paragraph>
|
||||||
</paragraph>
|
|
||||||
<paragraph>
|
|
||||||
four
|
|
||||||
</paragraph>
|
|
||||||
</quote>
|
</quote>
|
||||||
</quote>
|
</quote>
|
||||||
</document>
|
</document>
|
||||||
|
@@ -6,14 +6,10 @@ export const input = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>
|
||||||
<hashtag>
|
<hashtag>two</hashtag>
|
||||||
two
|
|
||||||
</hashtag>
|
|
||||||
</link>
|
</link>
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</quote>
|
</quote>
|
||||||
|
@@ -7,14 +7,10 @@ export const input = (
|
|||||||
<document>
|
<document>
|
||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>one</link>
|
||||||
one
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>two</link>
|
||||||
two
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</quote>
|
</quote>
|
||||||
</document>
|
</document>
|
||||||
|
@@ -5,9 +5,7 @@ import h from '../helpers/h'
|
|||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph thing="value">
|
<paragraph thing="value">one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -5,9 +5,7 @@ import h from '../helpers/h'
|
|||||||
export const input = (
|
export const input = (
|
||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>one</paragraph>
|
||||||
one
|
|
||||||
</paragraph>
|
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
)
|
)
|
||||||
|
@@ -7,9 +7,7 @@ export const input = (
|
|||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>
|
||||||
<hashtag>
|
<hashtag>one</hashtag>
|
||||||
one
|
|
||||||
</hashtag>
|
|
||||||
</link>
|
</link>
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
|
@@ -6,9 +6,7 @@ export const input = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link thing="value">
|
<link thing="value">one</link>
|
||||||
one
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -6,9 +6,7 @@ export const input = (
|
|||||||
<value>
|
<value>
|
||||||
<document>
|
<document>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<link>
|
<link>one</link>
|
||||||
one
|
|
||||||
</link>
|
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</document>
|
</document>
|
||||||
</value>
|
</value>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Block,
|
Block,
|
||||||
Change,
|
Change,
|
||||||
@@ -29,9 +28,14 @@ function create(name, validate) {
|
|||||||
function check(isRequired, props, propName, componentName, location) {
|
function check(isRequired, props, propName, componentName, location) {
|
||||||
const value = props[propName]
|
const value = props[propName]
|
||||||
if (value == null && !isRequired) return null
|
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
|
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) {
|
function propType(...args) {
|
||||||
|
@@ -8,17 +8,22 @@ import { basename, extname, resolve } from 'path'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const categoryDir = resolve(__dirname)
|
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, () => {
|
suite(category, () => {
|
||||||
set('iterations', 50)
|
set('iterations', 50)
|
||||||
set('mintime', 1000)
|
set('mintime', 1000)
|
||||||
|
|
||||||
const benchmarkDir = resolve(categoryDir, 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 dir = resolve(benchmarkDir, benchmark)
|
||||||
const module = require(dir)
|
const module = require(dir)
|
||||||
const fn = module.default
|
const fn = module.default
|
||||||
|
@@ -18,7 +18,8 @@ export const input = (
|
|||||||
<quote>
|
<quote>
|
||||||
<paragraph>
|
<paragraph>
|
||||||
<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>
|
||||||
</paragraph>
|
</paragraph>
|
||||||
</quote>
|
</quote>
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Types from 'prop-types'
|
import Types from 'prop-types'
|
||||||
@@ -15,7 +14,7 @@ import {
|
|||||||
IS_FIREFOX,
|
IS_FIREFOX,
|
||||||
IS_IOS,
|
IS_IOS,
|
||||||
IS_ANDROID,
|
IS_ANDROID,
|
||||||
SUPPORTED_EVENTS
|
SUPPORTED_EVENTS,
|
||||||
} from '../constants/environment'
|
} from '../constants/environment'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,7 +32,6 @@ const debug = Debug('slate:content')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Content extends React.Component {
|
class Content extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property types.
|
* Property types.
|
||||||
*
|
*
|
||||||
@@ -77,8 +75,8 @@ class Content extends React.Component {
|
|||||||
this.tmp.key = 0
|
this.tmp.key = 0
|
||||||
this.tmp.isUpdatingSelection = false
|
this.tmp.isUpdatingSelection = false
|
||||||
|
|
||||||
EVENT_HANDLERS.forEach((handler) => {
|
EVENT_HANDLERS.forEach(handler => {
|
||||||
this[handler] = (event) => {
|
this[handler] = event => {
|
||||||
this.onEvent(handler, event)
|
this.onEvent(handler, event)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -96,7 +94,10 @@ class Content extends React.Component {
|
|||||||
const { editor } = this.props
|
const { editor } = this.props
|
||||||
const window = getWindow(this.element)
|
const window = getWindow(this.element)
|
||||||
|
|
||||||
window.document.addEventListener('selectionchange', this.onNativeSelectionChange)
|
window.document.addEventListener(
|
||||||
|
'selectionchange',
|
||||||
|
this.onNativeSelectionChange
|
||||||
|
)
|
||||||
|
|
||||||
// COMPAT: Restrict scope of `beforeinput` to mobile.
|
// COMPAT: Restrict scope of `beforeinput` to mobile.
|
||||||
if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) {
|
if ((IS_IOS || IS_ANDROID) && SUPPORTED_EVENTS.beforeinput) {
|
||||||
@@ -118,7 +119,10 @@ class Content extends React.Component {
|
|||||||
const window = getWindow(this.element)
|
const window = getWindow(this.element)
|
||||||
|
|
||||||
if (window) {
|
if (window) {
|
||||||
window.document.removeEventListener('selectionchange', this.onNativeSelectionChange)
|
window.document.removeEventListener(
|
||||||
|
'selectionchange',
|
||||||
|
this.onNativeSelectionChange
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// COMPAT: Restrict scope of `beforeinput` to mobile.
|
// COMPAT: Restrict scope of `beforeinput` to mobile.
|
||||||
@@ -169,16 +173,14 @@ class Content extends React.Component {
|
|||||||
const range = findDOMRange(selection, window)
|
const range = findDOMRange(selection, window)
|
||||||
|
|
||||||
if (!range) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { startContainer, startOffset, endContainer, endOffset } = range
|
||||||
startContainer,
|
|
||||||
startOffset,
|
|
||||||
endContainer,
|
|
||||||
endOffset,
|
|
||||||
} = range
|
|
||||||
|
|
||||||
// If the new range matches the current selection, there is nothing to fix.
|
// 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"
|
// 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)
|
// to check both orientations here. (2017/10/31)
|
||||||
if (current) {
|
if (current) {
|
||||||
if (
|
if (
|
||||||
(
|
(startContainer == current.startContainer &&
|
||||||
startContainer == current.startContainer &&
|
|
||||||
startOffset == current.startOffset &&
|
startOffset == current.startOffset &&
|
||||||
endContainer == current.endContainer &&
|
endContainer == current.endContainer &&
|
||||||
endOffset == current.endOffset
|
endOffset == current.endOffset) ||
|
||||||
) ||
|
(startContainer == current.endContainer &&
|
||||||
(
|
|
||||||
startContainer == current.endContainer &&
|
|
||||||
startOffset == current.endOffset &&
|
startOffset == current.endOffset &&
|
||||||
endContainer == current.startContainer &&
|
endContainer == current.startContainer &&
|
||||||
endOffset == current.startOffset
|
endOffset == current.startOffset)
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -251,7 +249,7 @@ class Content extends React.Component {
|
|||||||
* @param {Element} element
|
* @param {Element} element
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ref = (element) => {
|
ref = element => {
|
||||||
this.element = element
|
this.element = element
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,13 +262,13 @@ class Content extends React.Component {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
isInEditor = (target) => {
|
isInEditor = target => {
|
||||||
const { element } = this
|
const { element } = this
|
||||||
// COMPAT: Text nodes don't have `isContentEditable` property. So, when
|
// COMPAT: Text nodes don't have `isContentEditable` property. So, when
|
||||||
// `target` is a text node use its parent node for check.
|
// `target` is a text node use its parent node for check.
|
||||||
const el = target.nodeType === 3 ? target.parentNode : target
|
const el = target.nodeType === 3 ? target.parentNode : target
|
||||||
return (
|
return (
|
||||||
(el.isContentEditable) &&
|
el.isContentEditable &&
|
||||||
(el === element || el.closest('[data-slate-editor]') === element)
|
(el === element || el.closest('[data-slate-editor]') === element)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -295,11 +293,7 @@ class Content extends React.Component {
|
|||||||
// programmatically while updating selection.
|
// programmatically while updating selection.
|
||||||
if (
|
if (
|
||||||
this.tmp.isUpdatingSelection &&
|
this.tmp.isUpdatingSelection &&
|
||||||
(
|
(handler == 'onSelect' || handler == 'onBlur' || handler == 'onFocus')
|
||||||
handler == 'onSelect' ||
|
|
||||||
handler == 'onBlur' ||
|
|
||||||
handler == 'onFocus'
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -368,7 +362,7 @@ class Content extends React.Component {
|
|||||||
* @param {InputEvent} event
|
* @param {InputEvent} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onNativeBeforeInput = (event) => {
|
onNativeBeforeInput = event => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
if (!this.isInEditor(event.target)) return
|
if (!this.isInEditor(event.target)) return
|
||||||
|
|
||||||
@@ -391,7 +385,7 @@ class Content extends React.Component {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const range = findRange(targetRange, editor.value)
|
const range = findRange(targetRange, editor.value)
|
||||||
|
|
||||||
editor.change((change) => {
|
editor.change(change => {
|
||||||
if (change.value.isInVoid) {
|
if (change.value.isInVoid) {
|
||||||
change.collapseToStartOfNextText()
|
change.collapseToStartOfNextText()
|
||||||
} else {
|
} else {
|
||||||
@@ -407,7 +401,8 @@ class Content extends React.Component {
|
|||||||
// `dataTransfer` should have the text for the `insertReplacementText`
|
// `dataTransfer` should have the text for the `insertReplacementText`
|
||||||
// input type, but Safari uses `insertText` for spell check replacements
|
// input type, but Safari uses `insertText` for spell check replacements
|
||||||
// and sets `data` to `null`.
|
// and sets `data` to `null`.
|
||||||
const text = event.data == null
|
const text =
|
||||||
|
event.data == null
|
||||||
? event.dataTransfer.getData('text/plain')
|
? event.dataTransfer.getData('text/plain')
|
||||||
: event.data
|
: event.data
|
||||||
|
|
||||||
@@ -419,7 +414,7 @@ class Content extends React.Component {
|
|||||||
const { selection } = value
|
const { selection } = value
|
||||||
const range = findRange(targetRange, value)
|
const range = findRange(targetRange, value)
|
||||||
|
|
||||||
editor.change((change) => {
|
editor.change(change => {
|
||||||
change.insertTextAtRange(range, text, selection.marks)
|
change.insertTextAtRange(range, text, selection.marks)
|
||||||
|
|
||||||
// If the text was successfully inserted, and the selection had marks
|
// If the text was successfully inserted, and the selection had marks
|
||||||
@@ -443,7 +438,7 @@ class Content extends React.Component {
|
|||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onNativeSelectionChange = throttle((event) => {
|
onNativeSelectionChange = throttle(event => {
|
||||||
if (this.props.readOnly) return
|
if (this.props.readOnly) return
|
||||||
|
|
||||||
const window = getWindow(event.target)
|
const window = getWindow(event.target)
|
||||||
@@ -526,7 +521,7 @@ class Content extends React.Component {
|
|||||||
autoCorrect={props.autoCorrect ? 'on' : 'off'}
|
autoCorrect={props.autoCorrect ? 'on' : 'off'}
|
||||||
spellCheck={spellCheck}
|
spellCheck={spellCheck}
|
||||||
style={style}
|
style={style}
|
||||||
role={readOnly ? null : (role || 'textbox')}
|
role={readOnly ? null : role || 'textbox'}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
// COMPAT: The Grammarly Chrome extension works by changing the DOM out
|
// COMPAT: The Grammarly Chrome extension works by changing the DOM out
|
||||||
// from under `contenteditable` elements, which leads to weird behaviors
|
// from under `contenteditable` elements, which leads to weird behaviors
|
||||||
@@ -567,14 +562,13 @@ class Content extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mix in handler prop types.
|
* Mix in handler prop types.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
EVENT_HANDLERS.forEach((handler) => {
|
EVENT_HANDLERS.forEach(handler => {
|
||||||
Content.propTypes[handler] = Types.func.isRequired
|
Content.propTypes[handler] = Types.func.isRequired
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import Portal from 'react-portal'
|
import Portal from 'react-portal'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -28,7 +27,6 @@ const debug = Debug('slate:editor')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Editor extends React.Component {
|
class Editor extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property types.
|
* Property types.
|
||||||
*
|
*
|
||||||
@@ -95,7 +93,7 @@ class Editor extends React.Component {
|
|||||||
this.state.value = change.value
|
this.state.value = change.value
|
||||||
|
|
||||||
// Create a bound event handler for each event.
|
// Create a bound event handler for each event.
|
||||||
EVENT_HANDLERS.forEach((handler) => {
|
EVENT_HANDLERS.forEach(handler => {
|
||||||
this[handler] = (...args) => {
|
this[handler] = (...args) => {
|
||||||
this.onEvent(handler, ...args)
|
this.onEvent(handler, ...args)
|
||||||
}
|
}
|
||||||
@@ -109,7 +107,7 @@ class Editor extends React.Component {
|
|||||||
* @param {Object} props
|
* @param {Object} props
|
||||||
*/
|
*/
|
||||||
|
|
||||||
componentWillReceiveProps = (props) => {
|
componentWillReceiveProps = props => {
|
||||||
let { schema, stack } = this
|
let { schema, stack } = this
|
||||||
|
|
||||||
// Increment the updates counter as a baseline.
|
// 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
|
// 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.
|
// 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)
|
const plugins = this.resolvePlugins(props.plugins, props.schema)
|
||||||
stack = Stack.create({ plugins })
|
stack = Stack.create({ plugins })
|
||||||
schema = Schema.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
|
// 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.
|
// the updates, then warn the user that they may be doing something wrong.
|
||||||
if (this.tmp.resolves > 5 && this.tmp.resolves == this.tmp.updates) {
|
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
|
* @param {Change} change
|
||||||
*/
|
*/
|
||||||
|
|
||||||
queueChange = (change) => {
|
queueChange = change => {
|
||||||
if (change.operations.size) {
|
if (change.operations.size) {
|
||||||
debug('queueChange', { change })
|
debug('queueChange', { change })
|
||||||
this.tmp.change = change
|
this.tmp.change = change
|
||||||
@@ -239,7 +242,7 @@ class Editor extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
onEvent = (handler, event) => {
|
onEvent = (handler, event) => {
|
||||||
this.change((change) => {
|
this.change(change => {
|
||||||
this.stack.run(handler, event, change, this)
|
this.stack.run(handler, event, change, this)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -250,7 +253,7 @@ class Editor extends React.Component {
|
|||||||
* @param {Change} change
|
* @param {Change} change
|
||||||
*/
|
*/
|
||||||
|
|
||||||
onChange = (change) => {
|
onChange = change => {
|
||||||
debug('onChange', { change })
|
debug('onChange', { change })
|
||||||
|
|
||||||
this.stack.run('onChange', change, this)
|
this.stack.run('onChange', change, this)
|
||||||
@@ -271,7 +274,11 @@ class Editor extends React.Component {
|
|||||||
|
|
||||||
const children = this.stack
|
const children = this.stack
|
||||||
.map('renderPortal', this.value, this)
|
.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 props = { ...this.props, children }
|
||||||
const tree = this.stack.render('renderEditor', props, this)
|
const tree = this.stack.render('renderEditor', props, this)
|
||||||
@@ -296,7 +303,7 @@ class Editor extends React.Component {
|
|||||||
const beforePlugin = BeforePlugin()
|
const beforePlugin = BeforePlugin()
|
||||||
const afterPlugin = AfterPlugin()
|
const afterPlugin = AfterPlugin()
|
||||||
const editorPlugin = {
|
const editorPlugin = {
|
||||||
schema: schema || {}
|
schema: schema || {},
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const prop of PLUGINS_PROPS) {
|
for (const prop of PLUGINS_PROPS) {
|
||||||
@@ -313,17 +320,10 @@ class Editor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [beforePlugin, editorPlugin, ...(plugins || []), afterPlugin]
|
||||||
beforePlugin,
|
|
||||||
editorPlugin,
|
|
||||||
...(plugins || []),
|
|
||||||
afterPlugin
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mix in the property types for the event handlers.
|
* Mix in the property types for the event handlers.
|
||||||
*/
|
*/
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Types from 'prop-types'
|
import Types from 'prop-types'
|
||||||
@@ -21,7 +20,6 @@ const debug = Debug('slate:leaves')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Leaf extends React.Component {
|
class Leaf extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property types.
|
* Property types.
|
||||||
*
|
*
|
||||||
@@ -85,14 +83,10 @@ class Leaf extends React.Component {
|
|||||||
const { node, index } = this.props
|
const { node, index } = this.props
|
||||||
const offsetKey = OffsetKey.stringify({
|
const offsetKey = OffsetKey.stringify({
|
||||||
key: node.key,
|
key: node.key,
|
||||||
index
|
index,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return <span data-offset-key={offsetKey}>{this.renderMarks()}</span>
|
||||||
<span data-offset-key={offsetKey}>
|
|
||||||
{this.renderMarks()}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,7 +136,6 @@ class Leaf extends React.Component {
|
|||||||
// Otherwise, just return the text.
|
// Otherwise, just return the text.
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import ImmutableTypes from 'react-immutable-proptypes'
|
import ImmutableTypes from 'react-immutable-proptypes'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -24,7 +23,6 @@ const debug = Debug('slate:node')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Node extends React.Component {
|
class Node extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property types.
|
* Property types.
|
||||||
*
|
*
|
||||||
@@ -62,10 +60,14 @@ class Node extends React.Component {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
shouldComponentUpdate = (nextProps) => {
|
shouldComponentUpdate = nextProps => {
|
||||||
const { props } = this
|
const { props } = this
|
||||||
const { stack } = props.editor
|
const { stack } = props.editor
|
||||||
const shouldUpdate = stack.find('shouldNodeComponentUpdate', props, nextProps)
|
const shouldUpdate = stack.find(
|
||||||
|
'shouldNodeComponentUpdate',
|
||||||
|
props,
|
||||||
|
nextProps
|
||||||
|
)
|
||||||
const n = nextProps
|
const n = nextProps
|
||||||
const p = props
|
const p = props
|
||||||
|
|
||||||
@@ -78,7 +80,9 @@ class Node extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (shouldUpdate === false) {
|
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)
|
let placeholder = stack.find('renderPlaceholder', props)
|
||||||
|
|
||||||
if (placeholder) {
|
if (placeholder) {
|
||||||
placeholder = React.cloneElement(placeholder, { key: `${node.key}-placeholder` })
|
placeholder = React.cloneElement(placeholder, {
|
||||||
|
key: `${node.key}-placeholder`,
|
||||||
|
})
|
||||||
children = [placeholder, ...children]
|
children = [placeholder, ...children]
|
||||||
}
|
}
|
||||||
|
|
||||||
const element = stack.find('renderNode', { ...props, attributes, children })
|
const element = stack.find('renderNode', {
|
||||||
|
...props,
|
||||||
|
attributes,
|
||||||
|
children,
|
||||||
|
})
|
||||||
|
|
||||||
return node.isVoid
|
return node.isVoid ? <Void {...this.props}>{element}</Void> : element
|
||||||
? <Void {...this.props}>{element}</Void>
|
|
||||||
: element
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,7 +193,6 @@ class Node extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import ImmutableTypes from 'react-immutable-proptypes'
|
import ImmutableTypes from 'react-immutable-proptypes'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
@@ -22,7 +21,6 @@ const debug = Debug('slate:node')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Text extends React.Component {
|
class Text extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property types.
|
* Property types.
|
||||||
*
|
*
|
||||||
@@ -69,7 +67,7 @@ class Text extends React.Component {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
shouldComponentUpdate = (nextProps) => {
|
shouldComponentUpdate = nextProps => {
|
||||||
const { props } = this
|
const { props } = this
|
||||||
const n = nextProps
|
const n = nextProps
|
||||||
const p = props
|
const p = props
|
||||||
@@ -109,7 +107,7 @@ class Text extends React.Component {
|
|||||||
const { document } = value
|
const { document } = value
|
||||||
const { key } = node
|
const { key } = node
|
||||||
|
|
||||||
const decs = decorations.filter((d) => {
|
const decs = decorations.filter(d => {
|
||||||
const { startKey, endKey } = d
|
const { startKey, endKey } = d
|
||||||
if (startKey == key || endKey == key) return true
|
if (startKey == key || endKey == key) return true
|
||||||
const startsBefore = document.areDescendantsSorted(startKey, key)
|
const startsBefore = document.areDescendantsSorted(startKey, key)
|
||||||
@@ -162,7 +160,6 @@ class Text extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import Debug from 'debug'
|
import Debug from 'debug'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import SlateTypes from 'slate-prop-types'
|
import SlateTypes from 'slate-prop-types'
|
||||||
@@ -21,7 +20,6 @@ const debug = Debug('slate:void')
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Void extends React.Component {
|
class Void extends React.Component {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property types.
|
* Property types.
|
||||||
*
|
*
|
||||||
@@ -78,11 +76,7 @@ class Void extends React.Component {
|
|||||||
</Tag>
|
</Tag>
|
||||||
)
|
)
|
||||||
|
|
||||||
const content = (
|
const content = <Tag draggable={readOnly ? null : true}>{children}</Tag>
|
||||||
<Tag draggable={readOnly ? null : true}>
|
|
||||||
{children}
|
|
||||||
</Tag>
|
|
||||||
)
|
|
||||||
|
|
||||||
this.debug('render', { props })
|
this.debug('render', { props })
|
||||||
|
|
||||||
@@ -110,7 +104,14 @@ class Void extends React.Component {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
renderText = () => {
|
renderText = () => {
|
||||||
const { block, decorations, isSelected, node, readOnly, editor } = this.props
|
const {
|
||||||
|
block,
|
||||||
|
decorations,
|
||||||
|
isSelected,
|
||||||
|
node,
|
||||||
|
readOnly,
|
||||||
|
editor,
|
||||||
|
} = this.props
|
||||||
const child = node.getFirstText()
|
const child = node.getFirstText()
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
@@ -125,7 +126,6 @@ class Void extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import browser from 'is-in-browser'
|
import browser from 'is-in-browser'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,9 +25,7 @@ const BROWSER_RULES = [
|
|||||||
* @type {Array}
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const EVENT_RULES = [
|
const EVENT_RULES = [['beforeinput', el => 'onbeforeinput' in el]]
|
||||||
['beforeinput', el => 'onbeforeinput' in el]
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Operating system matching rules.
|
* Operating system matching rules.
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Event handlers used by Slate plugins.
|
* Event handlers used by Slate plugins.
|
||||||
*
|
*
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import { isKeyHotkey } from 'is-hotkey'
|
import { isKeyHotkey } from 'is-hotkey'
|
||||||
|
|
||||||
import { IS_IOS, IS_MAC } from './environment'
|
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_BACKWARD_MAC = isKeyHotkey('ctrl+h')
|
||||||
const DELETE_CHAR_FORWARD_MAC = isKeyHotkey('ctrl+d')
|
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_BACKWARD = e =>
|
||||||
const DELETE_CHAR_FORWARD = e => DELETE_FORWARD(e) || (IS_APPLE && DELETE_CHAR_FORWARD_MAC(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_BACKWARD_MAC = isKeyHotkey('cmd+backspace')
|
||||||
const DELETE_LINE_FORWARD_MAC = isKeyHotkey('ctrl+k')
|
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_BACKWARD_PC = isKeyHotkey('ctrl+backspace')
|
||||||
const DELETE_WORD_FORWARD_MAC = isKeyHotkey('option+delete')
|
const DELETE_WORD_FORWARD_MAC = isKeyHotkey('option+delete')
|
||||||
const DELETE_WORD_FORWARD_PC = isKeyHotkey('ctrl+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_BACKWARD = e =>
|
||||||
const DELETE_WORD_FORWARD = e => IS_APPLE ? DELETE_WORD_FORWARD_MAC(e) : DELETE_WORD_FORWARD_PC(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 RIGHT_ARROW = isKeyHotkey('right')
|
||||||
const LEFT_ARROW = isKeyHotkey('left')
|
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 UNDO = isKeyHotkey('mod+z')
|
||||||
const REDO_MAC = isKeyHotkey('mod+shift+z')
|
const REDO_MAC = isKeyHotkey('mod+shift+z')
|
||||||
const REDO_PC = isKeyHotkey('mod+y')
|
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_MAC = isKeyHotkey('ctrl+t')
|
||||||
const TRANSPOSE_CHARACTER = e => IS_APPLE && TRANSPOSE_CHARACTER_MAC(e)
|
const TRANSPOSE_CHARACTER = e => IS_APPLE && TRANSPOSE_CHARACTER_MAC(e)
|
||||||
|
|
||||||
const CONTENTEDITABLE = e => (
|
const CONTENTEDITABLE = e =>
|
||||||
BOLD(e) ||
|
BOLD(e) ||
|
||||||
DELETE_CHAR_BACKWARD(e) ||
|
DELETE_CHAR_BACKWARD(e) ||
|
||||||
DELETE_CHAR_FORWARD(e) ||
|
DELETE_CHAR_FORWARD(e) ||
|
||||||
@@ -87,16 +90,14 @@ const CONTENTEDITABLE = e => (
|
|||||||
SPLIT_BLOCK(e) ||
|
SPLIT_BLOCK(e) ||
|
||||||
TRANSPOSE_CHARACTER(e) ||
|
TRANSPOSE_CHARACTER(e) ||
|
||||||
UNDO(e)
|
UNDO(e)
|
||||||
)
|
|
||||||
|
|
||||||
const COMPOSING = e => (
|
const COMPOSING = e =>
|
||||||
e.key == 'ArrowDown' ||
|
e.key == 'ArrowDown' ||
|
||||||
e.key == 'ArrowLeft' ||
|
e.key == 'ArrowLeft' ||
|
||||||
e.key == 'ArrowRight' ||
|
e.key == 'ArrowRight' ||
|
||||||
e.key == 'ArrowUp' ||
|
e.key == 'ArrowUp' ||
|
||||||
e.key == 'Backspace' ||
|
e.key == 'Backspace' ||
|
||||||
e.key == 'Enter'
|
e.key == 'Enter'
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export.
|
* Export.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user