diff --git a/lib/components/editor.js b/lib/components/editor.js index 01db1b838..429ee4c5d 100644 --- a/lib/components/editor.js +++ b/lib/components/editor.js @@ -3,6 +3,7 @@ import Content from './content' import CorePlugin from '../plugins/core' import React from 'react' import State from '../models/state' +import typeOf from 'type-of' /** * Noop. @@ -242,21 +243,26 @@ class Editor extends React.Component { * * @param {Mark} mark * @param {Set} marks - * @return {Element} + * @return {Component or Object or String} */ renderMark = (mark, marks) => { for (const plugin of this.state.plugins) { if (!plugin.renderMark) continue - let component = plugin.renderMark(mark, marks, this.state.state, this) + let ret = plugin.renderMark(mark, marks, this.state.state, this) - // plugin.renderMak can return a map of style - if (component && !(typeof component === 'function')) { - const style = component - component = (props => {props.children}) + // Handle React components that aren't stateless functions. + if (ret && ret.prototype && ret.prototype.isReactComponent) return ret + + // Handle all other types... + switch (typeOf(ret)) { + case 'function': + return ret + case 'object': + return props => {props.children} + case 'string': + return props => {props.children} } - - if (component) return component } } diff --git a/lib/components/leaf.js b/lib/components/leaf.js index 712a184be..83b03bb3c 100644 --- a/lib/components/leaf.js +++ b/lib/components/leaf.js @@ -3,22 +3,6 @@ import OffsetKey from '../utils/offset-key' import React from 'react' import ReactDOM from 'react-dom' -/** - * Find the deepest child (text node) of a DOM node - * @param {DOMNode} node - * @return {DOMNode} - */ - -function findDeepestNode(node) { - let child = node.firstChild - - if (child) { - return findDeepestNode(child) - } - - return node -} - /** * Leaf. */ @@ -168,7 +152,7 @@ class Leaf extends React.Component { key={this.tmp.renders} data-offset-key={offsetKey} > - {this.renderWithMarks()} + {this.renderMarks()} ) } @@ -187,33 +171,29 @@ class Leaf extends React.Component { return text } - renderMark(inner, mark) { - const { node, index, renderMark, marks } = this.props - const offsetKey = OffsetKey.stringify({ - key: node.key, - index - }) + renderMarks() { + const { marks, renderMark } = this.props + const text = this.renderText() - const MarkComponent = renderMark(mark, marks) - if (!MarkComponent) { - return inner - } - - return ( - - {inner} - - ) + return marks.reduce((children, mark) => { + const Component = renderMark(mark, marks) + if (!Component) return children + return {children} + }, text) } +} - renderWithMarks() { - const { marks, renderMark } = this.props - const element = marks.reduce(this.renderMark, this.renderText(), this) +/** + * Find the deepest descendant of a DOM `element`. + * + * @param {Element} node + * @return {Element} + */ - return element - } +function findDeepestNode(element) { + return element.firstChild + ? findDeepestNode(element.firstChild) + : element } /** diff --git a/lib/components/void.js b/lib/components/void.js index 66eb696bd..6f977ca27 100644 --- a/lib/components/void.js +++ b/lib/components/void.js @@ -7,6 +7,14 @@ import ReactDOM from 'react-dom' import keycode from 'keycode' import { IS_FIREFOX } from '../utils/environment' +/** + * Noop. + * + * @type {Function} + */ + +function noop() {} + /** * Void. * @@ -156,7 +164,7 @@ class Void extends React.Component { return ( { - return - } - } /** diff --git a/test/rendering/fixtures/custom-mark-multiple/index.js b/test/rendering/fixtures/custom-mark-multiple/index.js index b2bc2451e..be0673596 100644 --- a/test/rendering/fixtures/custom-mark-multiple/index.js +++ b/test/rendering/fixtures/custom-mark-multiple/index.js @@ -16,10 +16,12 @@ const BOLD_ITALIC = { export function renderMark(mark, marks) { if ( marks.size > 1 && - marks.some(m => m.type == 'italic') && - marks.some(m => m.type == 'bold') + marks.some(m => m.type == 'bold') && + marks.some(m => m.type == 'italic') ) { - return mark.type == 'bold' ? BOLD_ITALIC : undefined + return mark.type == 'bold' + ? BOLD_ITALIC + : null } if (mark.type == 'bold') return BOLD diff --git a/test/rendering/fixtures/custom-mark-with-component/index.js b/test/rendering/fixtures/custom-mark-with-component/index.js new file mode 100644 index 000000000..dd9b92291 --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-component/index.js @@ -0,0 +1,12 @@ + +import React from 'react' + +class Bold extends React.Component { + render() { + return {this.props.children} + } +} + +export function renderMark(mark) { + if (mark.type == 'bold') return Bold +} diff --git a/test/rendering/fixtures/custom-mark/input.yaml b/test/rendering/fixtures/custom-mark-with-component/input.yaml similarity index 100% rename from test/rendering/fixtures/custom-mark/input.yaml rename to test/rendering/fixtures/custom-mark-with-component/input.yaml diff --git a/test/rendering/fixtures/custom-mark-with-component/output.html b/test/rendering/fixtures/custom-mark-with-component/output.html new file mode 100644 index 000000000..5d51e1900 --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-component/output.html @@ -0,0 +1,10 @@ + +
+
+ + one + two + three + +
+
diff --git a/test/rendering/fixtures/custom-mark/index.js b/test/rendering/fixtures/custom-mark-with-function/index.js similarity index 61% rename from test/rendering/fixtures/custom-mark/index.js rename to test/rendering/fixtures/custom-mark-with-function/index.js index 119a06836..14185210a 100644 --- a/test/rendering/fixtures/custom-mark/index.js +++ b/test/rendering/fixtures/custom-mark-with-function/index.js @@ -1,8 +1,8 @@ import React from 'react' -const BOLD = { - fontWeight: 'bold' +function BOLD(props) { + return {props.children} } export function renderMark(mark) { diff --git a/test/rendering/fixtures/custom-mark-with-function/input.yaml b/test/rendering/fixtures/custom-mark-with-function/input.yaml new file mode 100644 index 000000000..e5830723f --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-function/input.yaml @@ -0,0 +1,12 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: text + ranges: + - text: one + - text: two + marks: + - type: bold + - text: three diff --git a/test/rendering/fixtures/custom-mark-with-function/output.html b/test/rendering/fixtures/custom-mark-with-function/output.html new file mode 100644 index 000000000..5d51e1900 --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-function/output.html @@ -0,0 +1,10 @@ + +
+
+ + one + two + three + +
+
diff --git a/test/rendering/fixtures/custom-mark-combine/index.js b/test/rendering/fixtures/custom-mark-with-mixed/index.js similarity index 76% rename from test/rendering/fixtures/custom-mark-combine/index.js rename to test/rendering/fixtures/custom-mark-with-mixed/index.js index e06b029cc..59ad5fc67 100644 --- a/test/rendering/fixtures/custom-mark-combine/index.js +++ b/test/rendering/fixtures/custom-mark-with-mixed/index.js @@ -5,7 +5,9 @@ const BOLD = { fontWeight: 'bold' } -const ITALIC = (props => {props.children}) +function ITALIC(props) { + return {props.children} +} export function renderMark(mark, marks) { if (mark.type == 'bold') return BOLD diff --git a/test/rendering/fixtures/custom-mark-combine/input.yaml b/test/rendering/fixtures/custom-mark-with-mixed/input.yaml similarity index 100% rename from test/rendering/fixtures/custom-mark-combine/input.yaml rename to test/rendering/fixtures/custom-mark-with-mixed/input.yaml diff --git a/test/rendering/fixtures/custom-mark-combine/output.html b/test/rendering/fixtures/custom-mark-with-mixed/output.html similarity index 100% rename from test/rendering/fixtures/custom-mark-combine/output.html rename to test/rendering/fixtures/custom-mark-with-mixed/output.html diff --git a/test/rendering/fixtures/custom-mark-with-object/index.js b/test/rendering/fixtures/custom-mark-with-object/index.js new file mode 100644 index 000000000..3f8c1239c --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-object/index.js @@ -0,0 +1,10 @@ + +import React from 'react' + +export function renderMark(mark) { + if (mark.type == 'bold') { + return { + fontWeight: 'bold' + } + } +} diff --git a/test/rendering/fixtures/custom-mark-with-object/input.yaml b/test/rendering/fixtures/custom-mark-with-object/input.yaml new file mode 100644 index 000000000..e5830723f --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-object/input.yaml @@ -0,0 +1,12 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: text + ranges: + - text: one + - text: two + marks: + - type: bold + - text: three diff --git a/test/rendering/fixtures/custom-mark/output.html b/test/rendering/fixtures/custom-mark-with-object/output.html similarity index 100% rename from test/rendering/fixtures/custom-mark/output.html rename to test/rendering/fixtures/custom-mark-with-object/output.html diff --git a/test/rendering/fixtures/custom-mark-with-string/index.js b/test/rendering/fixtures/custom-mark-with-string/index.js new file mode 100644 index 000000000..1c39489a9 --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-string/index.js @@ -0,0 +1,6 @@ + +import React from 'react' + +export function renderMark(mark) { + if (mark.type == 'bold') return 'bold' +} diff --git a/test/rendering/fixtures/custom-mark-with-string/input.yaml b/test/rendering/fixtures/custom-mark-with-string/input.yaml new file mode 100644 index 000000000..e5830723f --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-string/input.yaml @@ -0,0 +1,12 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: text + ranges: + - text: one + - text: two + marks: + - type: bold + - text: three diff --git a/test/rendering/fixtures/custom-mark-with-string/output.html b/test/rendering/fixtures/custom-mark-with-string/output.html new file mode 100644 index 000000000..37e4d0e63 --- /dev/null +++ b/test/rendering/fixtures/custom-mark-with-string/output.html @@ -0,0 +1,10 @@ + +
+
+ + one + two + three + +
+