diff --git a/src/components/ControlPanel/ControlPane.css b/src/components/ControlPanel/ControlPane.css
index 8251a3ee..7d496776 100644
--- a/src/components/ControlPanel/ControlPane.css
+++ b/src/components/ControlPanel/ControlPane.css
@@ -10,8 +10,7 @@
& input,
& textarea,
- & select,
- & div[contenteditable=true] {
+ & select {
@apply --input;
}
}
diff --git a/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.css b/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.css
index 7783ab5b..02877169 100644
--- a/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.css
+++ b/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.css
@@ -3,6 +3,7 @@
}
.nc-rawEditor-rawEditor {
+ @apply(--input);
position: relative;
overflow: hidden;
overflow-x: auto;
diff --git a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.css b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.css
index ac2ce2ca..384334ab 100644
--- a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.css
+++ b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.css
@@ -14,6 +14,7 @@
}
.nc-visualEditor-editor {
+ @apply(--input);
position: relative;
overflow: hidden;
overflow-x: auto;
diff --git a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/renderers.js b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/renderers.js
index 8abedb64..52a04427 100644
--- a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/renderers.js
+++ b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/renderers.js
@@ -8,65 +8,96 @@ import cn from 'classnames';
* by us when we manually deserialize from Remark's MDAST to Slate's AST.
*/
+/**
+ * Mark Components
+ */
+const Bold = props => {props.children};
+const Italic = props => {props.children};
+const Strikethrough = props => {props.children};
+const Code = props => {props.children}
;
+
+/**
+ * Node Components
+ */
+const Paragraph = props =>
{props.children}
;
+const ListItem = props => {props.children};
+const Quote = props => {props.children}
;
+const CodeBlock = props => {props.children}
;
+const HeadingOne = props => {props.children}
;
+const HeadingTwo = props => {props.children}
;
+const HeadingThree = props => {props.children}
;
+const HeadingFour = props => {props.children}
;
+const HeadingFive = props => {props.children}
;
+const HeadingSix = props => {props.children}
;
+const Table = props => ;
+const TableRow = props => {props.children}
;
+const TableCell = props => {props.children} | ;
+const ThematicBreak = props =>
;
+const BulletedList = props => ;
+const NumberedList = props => (
+ {props.children}
+);
+const Link = props => {
+ const data = props.node.get('data');
+ const marks = data.get('marks');
+ const url = data.get('url');
+ const title = data.get('title');
+ const link = {props.children};
+ const result = !marks ? link : marks.reduce((acc, mark) => {
+ const MarkComponent = MARK_COMPONENTS[mark.type];
+ return {acc};
+ }, link);
+ return result;
+};
+const Image = props => {
+ const data = props.node.get('data');
+ const marks = data.get('marks');
+ const url = data.get('url');
+ const title = data.get('title');
+ const alt = data.get('alt');
+ const image = ;
+ const result = !marks ? image : marks.reduce((acc, mark) => {
+ const MarkComponent = MARK_COMPONENTS[mark.type];
+ return {acc};
+ }, image);
+ return result;
+};
+const Shortcode = props => {
+ const { attributes, node, editor } = props;
+ const isSelected = editor.value.selection.hasFocusIn(node);
+ const className = cn('nc-visualEditor-shortcode', { ['nc-visualEditor-shortcodeSelected']: isSelected });
+ return {node.data.get('shortcode')}
;
+};
+
export const renderMark = props => {
switch (props.mark.type) {
- case bold: return props => {props.children};
- case italic: return props => {props.children};
- case strikethrough: return props => {props.children};
- case code: return props => {props.children}
;
+ case 'bold': return ;
+ case 'italic': return ;
+ case 'strikethrough': return ;
+ case 'code': return
;
}
};
export const renderNode = props => {
switch (props.node.type) {
- case 'paragraph': return props => {props.children}
;
- case 'list-item': return props => {props.children};
- case 'quote': return props => {props.children}
;
- case 'code': return props => {props.children}
;
- case 'heading-one': return props => {props.children}
;
- case 'heading-two': return props => {props.children}
;
- case 'heading-three': return props => {props.children}
;
- case 'heading-four': return props => {props.children}
;
- case 'heading-five': return props => {props.children}
;
- case 'heading-six': return props => {props.children}
;
- case 'table': return props => ;
- case 'table-row': return props => {props.children}
;
- case 'table-cell': return props => {props.children} | ;
- case 'thematic-break': return props =>
;
- case 'bulleted-list': return props => ;
- case 'numbered-list': return props => (
- {props.children}
- );
- case 'link': return props => {
- const data = props.node.get('data');
- const marks = data.get('marks');
- const url = data.get('url');
- const title = data.get('title');
- const link = {props.children};
- const result = !marks ? link : marks.reduce((acc, mark) => {
- const MarkComponent = MARK_COMPONENTS[mark.type];
- return {acc};
- }, link);
- return result;
- };
- case 'image': props => {
- const data = props.node.get('data');
- const marks = data.get('marks');
- const url = data.get('url');
- const title = data.get('title');
- const alt = data.get('alt');
- const image = ;
- const result = !marks ? image : marks.reduce((acc, mark) => {
- const MarkComponent = MARK_COMPONENTS[mark.type];
- return {acc};
- }, image);
- return result;
- };
- case 'shortcode': props => {
- const { attributes, node, editor } = props;
- const isSelected = editor.value.selection.hasFocusIn(node);
- const className = cn('nc-visualEditor-shortcode', { ['nc-visualEditor-shortcodeSelected']: isSelected });
- return {node.data.get('shortcode')}
;
- };
+ case 'paragraph': return ;
+ case 'list-item': return ;
+ case 'quote': return
;
+ case 'code': return ;
+ case 'heading-one': return ;
+ case 'heading-two': return ;
+ case 'heading-three': return ;
+ case 'heading-four': return ;
+ case 'heading-five': return ;
+ case 'heading-six': return ;
+ case 'table': return ;
+ case 'table-row': return ;
+ case 'table-cell': return ;
+ case 'thematic-break': return ;
+ case 'bulleted-list': return ;
+ case 'numbered-list': return ;
+ case 'link': return ;
+ case 'image': return ;
+ case 'shortcode': return ;
}
};
diff --git a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/validators.js b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/validators.js
index aa7a3248..d3c4e8d9 100644
--- a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/validators.js
+++ b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/validators.js
@@ -9,6 +9,7 @@ export function validateNode(node) {
* Validation of the document itself.
*/
if (node.kind === 'document') {
+ const doc = node;
/**
* If the editor is ever in an empty state, insert an empty
* paragraph block.
@@ -28,26 +29,45 @@ export function validateNode(node) {
/**
* Ensure that shortcodes are children of the root node.
*/
- const nestedShortcode = node.findDescendant(descendant => {
+ const nestedShortcode = doc.findDescendant(descendant => {
const { type, key } = descendant;
- return type === 'shortcode' && node.getParent(key).key !== node.key;
+ return type === 'shortcode' && doc.getParent(key).key !== doc.key;
});
if (nestedShortcode) {
- return change => change.unwrapNodeByKey(node.key);
+ const unwrapShortcode = change => {
+ const key = nestedShortcode.key;
+ const newDoc = change.value.document;
+ const newParent = newDoc.getParent(key);
+ const docIsParent = newParent.key === newDoc.key;
+ const newParentParent = newDoc.getParent(newParent.key);
+ const docIsParentParent = newParentParent && newParentParent.key === newDoc.key;
+ if (docIsParent) {
+ return change;
+ }
+ /**
+ * Normalization happens by default, and causes all validation to
+ * restart with the result of a change upon execution. This unwrap loop
+ * could temporarily place a shortcode node in conflict with an outside
+ * plugin's schema, resulting in an infinite loop. To ensure against
+ * this, we turn off normalization until the last change.
+ */
+ change.unwrapNodeByKey(nestedShortcode.key, { normalize: docIsParentParent });
+ };
+ return unwrapShortcode;
}
/**
* Ensure that trailing shortcodes are followed by an empty paragraph.
*/
- const trailingShortcode = node.findDescendant(descendant => {
+ const trailingShortcode = doc.findDescendant(descendant => {
const { type, key } = descendant;
- return type === 'shortcode' && node.getBlocks().last().key === key;
+ return type === 'shortcode' && doc.getBlocks().last().key === key;
});
if (trailingShortcode) {
return change => {
const text = Text.create('');
const block = Block.create({ type: 'paragraph', nodes: [ text ] });
- return change.insertNodeByKey(node.key, node.get('nodes').size, block);
+ return change.insertNodeByKey(doc.key, doc.get('nodes').size, block);
};
}
}
diff --git a/src/components/Widgets/Markdown/serializers/slateRemark.js b/src/components/Widgets/Markdown/serializers/slateRemark.js
index a4e6c0de..cd6b83c9 100644
--- a/src/components/Widgets/Markdown/serializers/slateRemark.js
+++ b/src/components/Widgets/Markdown/serializers/slateRemark.js
@@ -249,7 +249,7 @@ function convertTextNode(node) {
/**
* Process Slate node leaves in preparation for MDAST transformation.
*/
-function processLeaves(leaves) {
+function processLeaves(leaf) {
/**
* Get an array of the mark types, converted to their MDAST equivalent
* types.