add markdown editor soft break support

This commit is contained in:
Shawn Erquhart 2017-08-31 11:03:08 -04:00
parent e43edf67b9
commit e408dcc27e
6 changed files with 41 additions and 19 deletions

View File

@ -156,6 +156,7 @@
"slate": "^0.21.0", "slate": "^0.21.0",
"slate-edit-list": "^0.7.1", "slate-edit-list": "^0.7.1",
"slate-edit-table": "^0.10.1", "slate-edit-table": "^0.10.1",
"slate-soft-break": "^0.3.0",
"slug": "^0.9.1", "slug": "^0.9.1",
"unified": "^6.1.4", "unified": "^6.1.4",
"unist-builder": "^1.0.2", "unist-builder": "^1.0.2",

View File

@ -1,3 +1,4 @@
import SlateSoftBreak from 'slate-soft-break';
import EditList from 'slate-edit-list'; import EditList from 'slate-edit-list';
import EditTable from 'slate-edit-table'; import EditTable from 'slate-edit-table';
@ -31,6 +32,8 @@ const SoftBreakOpts = {
export const SoftBreakConfigured = SoftBreak(SoftBreakOpts); export const SoftBreakConfigured = SoftBreak(SoftBreakOpts);
export const ParagraphSoftBreakConfigured = SlateSoftBreak({ onlyIn: ['paragraph'], shift: true });
const BackspaceCloseBlock = (options = {}) => ({ const BackspaceCloseBlock = (options = {}) => ({
onKeyDown(e, data, state) { onKeyDown(e, data, state) {
if (data.key != 'backspace') return; if (data.key != 'backspace') return;
@ -82,6 +85,7 @@ export const EditTableConfigured = EditTable(EditTableOpts);
const plugins = [ const plugins = [
SoftBreakConfigured, SoftBreakConfigured,
ParagraphSoftBreakConfigured,
BackspaceCloseBlockConfigured, BackspaceCloseBlockConfigured,
EditListConfigured, EditListConfigured,
EditTableConfigured, EditTableConfigured,

View File

@ -110,26 +110,11 @@ import registry from '../../../../lib/registry';
* Deserialize a Markdown string to an MDAST. * Deserialize a Markdown string to an MDAST.
*/ */
export const markdownToRemark = markdown => { export const markdownToRemark = markdown => {
/**
* Disabling tokenizers allows us to turn off features within the Remark
* parser.
*/
function disableTokenizers() {
/**
* Turn off soft breaks until we can properly support them across both
* editors.
*/
pull(this.Parser.prototype.inlineMethods, 'break');
}
/** /**
* Parse the Markdown string input to an MDAST. * Parse the Markdown string input to an MDAST.
*/ */
const parsed = unified() const parsed = unified()
.use(markdownToRemarkPlugin, { fences: true, pedantic: true, commonmark: true }) .use(markdownToRemarkPlugin, { fences: true, pedantic: true, commonmark: true })
.use(disableTokenizers)
.parse(markdown); .parse(markdown);
/** /**

View File

@ -231,6 +231,16 @@ function convertNode(node, nodes) {
return createBlock(slateType, nodes, { data }); return createBlock(slateType, nodes, { data });
} }
/**
* Breaks
*
* MDAST soft break nodes represent a trailing double space or trailing
* slash from a Markdown document. In Slate, these are simply transformed to
* line breaks within a text node.
*/
case 'break': {
return createText('\n');
}
/** /**
* Thematic Breaks * Thematic Breaks

View File

@ -1,4 +1,4 @@
import { get, isEmpty, concat, without, flatten } from 'lodash'; import { get, isEmpty, concat, without, flatten, flatMap, initial } from 'lodash';
import u from 'unist-builder'; import u from 'unist-builder';
/** /**
@ -56,6 +56,24 @@ function processCodeMark(markTypes) {
} }
/**
* Returns an array of one or more MDAST text nodes of the given type, derived
* from the text received. Certain transformations, such as line breaks, cause
* multiple nodes to be returned.
*/
function createTextNodes(text, type = 'html') {
/**
* Split the text string at line breaks, then map each substring to an array
* pair consisting of an MDAST text node followed by a break node. This will
* result in nested arrays, so we use `flatMap` to produce a flattened array,
* and `initial` to leave off the superfluous trailing break.
*/
const brokenText = text.split('\n');
const toPair = str => [u(type, str), u('break')];
return initial(flatMap(brokenText, toPair));
}
/** /**
* Wraps a text node in one or more mark nodes by placing the text node in an * Wraps a text node in one or more mark nodes by placing the text node in an
* array and using that as the `children` value of a mark node. The resulting * array and using that as the `children` value of a mark node. The resulting
@ -130,7 +148,7 @@ function convertTextNode(node) {
* MDAST node. * MDAST node.
*/ */
if (!node.ranges) { if (!node.ranges) {
return u('html', node.text); return createTextNodes(node.text);
} }
/** /**
@ -154,13 +172,13 @@ function convertTextNode(node) {
/** /**
* Create the base text node. * Create the base text node.
*/ */
const textNode = u(textNodeType, text); const textNodes = createTextNodes(text, textNodeType);
/** /**
* Recursively wrap the base text node in the individual mark nodes, if * Recursively wrap the base text node in the individual mark nodes, if
* any exist. * any exist.
*/ */
return wrapTextWithMarks(textNode, filteredMarkTypes); return textNodes.map(textNode => wrapTextWithMarks(textNode, filteredMarkTypes));
}); });
/** /**

View File

@ -7844,6 +7844,10 @@ slate-edit-table@^0.10.1:
dependencies: dependencies:
immutable "^3.8.1" immutable "^3.8.1"
slate-soft-break@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/slate-soft-break/-/slate-soft-break-0.3.0.tgz#3d28dea9e0aa4783ddcea785ff5db7277214d65f"
slate@^0.21.0: slate@^0.21.0:
version "0.21.4" version "0.21.4"
resolved "https://registry.yarnpkg.com/slate/-/slate-0.21.4.tgz#ae6113379cd838b7ec68ecd94834ce9741bc36f3" resolved "https://registry.yarnpkg.com/slate/-/slate-0.21.4.tgz#ae6113379cd838b7ec68ecd94834ce9741bc36f3"