Added support for custom renderers
This commit is contained in:
@ -2,7 +2,7 @@ import React, { PropTypes } from 'react';
|
|||||||
import MarkupIt, { Syntax, BLOCKS, STYLES, ENTITIES } from 'markup-it';
|
import MarkupIt, { Syntax, BLOCKS, STYLES, ENTITIES } from 'markup-it';
|
||||||
import htmlSyntax from 'markup-it/syntaxes/html';
|
import htmlSyntax from 'markup-it/syntaxes/html';
|
||||||
|
|
||||||
const defaultRenderers = {
|
const defaultSchema = {
|
||||||
[BLOCKS.DOCUMENT]: 'article',
|
[BLOCKS.DOCUMENT]: 'article',
|
||||||
[BLOCKS.TEXT]: null,
|
[BLOCKS.TEXT]: null,
|
||||||
[BLOCKS.CODE]: 'code',
|
[BLOCKS.CODE]: 'code',
|
||||||
@ -41,30 +41,28 @@ const defaultRenderers = {
|
|||||||
[ENTITIES.HARD_BREAK]: 'br'
|
[ENTITIES.HARD_BREAK]: 'br'
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderToken(token, index = 0, key = '0') {
|
function renderToken(schema, token, index = 0, key = '0') {
|
||||||
const type = token.get('type');
|
const type = token.get('type');
|
||||||
const data = token.get('data');
|
const data = token.get('data');
|
||||||
const text = token.get('text');
|
const text = token.get('text');
|
||||||
const raw = token.get('raw');
|
|
||||||
const tokens = token.get('tokens');
|
const tokens = token.get('tokens');
|
||||||
const nodeType = defaultRenderers[type];
|
const nodeType = schema[type];
|
||||||
key = `${key}.${index}`;
|
key = `${key}.${index}`;
|
||||||
|
|
||||||
// Only render if type is registered as renderer
|
// Only render if type is registered as renderer
|
||||||
if (typeof nodeType !== 'undefined') {
|
if (typeof nodeType !== 'undefined') {
|
||||||
let children = null;
|
let children = null;
|
||||||
if (tokens.size) {
|
if (tokens.size) {
|
||||||
children = tokens.map((token, idx) => renderToken(token, idx, key));
|
children = tokens.map((token, idx) => renderToken(schema, token, idx, key));
|
||||||
} else if (type === 'text') {
|
} else if (type === 'text') {
|
||||||
children = text;
|
children = text;
|
||||||
}
|
}
|
||||||
if (nodeType !== null) {
|
if (nodeType !== null) {
|
||||||
|
// If this is a function we want to pass the `token` as an argument
|
||||||
if (typeof nodeType === 'function') {
|
if (typeof nodeType === 'function') {
|
||||||
return nodeType(token);
|
return nodeType(token);
|
||||||
}
|
}
|
||||||
// If this is a react element
|
// If this is a react element
|
||||||
console.log(data.toJS());
|
|
||||||
return React.createElement(
|
return React.createElement(
|
||||||
nodeType,
|
nodeType,
|
||||||
{ key, ...data.toJS() }, // Add key as a prop
|
{ key, ...data.toJS() }, // Add key as a prop
|
||||||
@ -93,13 +91,14 @@ export default class MarkitupReactRenderer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { value } = this.props;
|
const { value, schema } = this.props;
|
||||||
const content = this.parser.toContent(value);
|
const content = this.parser.toContent(value);
|
||||||
return renderToken(content.get('token'));
|
return renderToken({ ...defaultSchema, ...schema }, content.get('token'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkitupReactRenderer.propTypes = {
|
MarkitupReactRenderer.propTypes = {
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
syntax: PropTypes.instanceOf(Syntax).isRequired
|
syntax: PropTypes.instanceOf(Syntax).isRequired,
|
||||||
|
schema: PropTypes.objectOf(PropTypes.node)
|
||||||
};
|
};
|
||||||
|
@ -2,8 +2,12 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
|
import { padStart } from 'lodash';
|
||||||
|
import { Map } from 'immutable';
|
||||||
|
import MarkupIt from 'markup-it';
|
||||||
import markdownSyntax from 'markup-it/syntaxes/markdown';
|
import markdownSyntax from 'markup-it/syntaxes/markdown';
|
||||||
import htmlSyntax from 'markup-it/syntaxes/html';
|
import htmlSyntax from 'markup-it/syntaxes/html';
|
||||||
|
import reInline from 'markup-it/syntaxes/markdown/re/inline';
|
||||||
import MarkitupReactRenderer from '../MarkitupReactRenderer';
|
import MarkitupReactRenderer from '../MarkitupReactRenderer';
|
||||||
|
|
||||||
describe('MarkitupReactRenderer', () => {
|
describe('MarkitupReactRenderer', () => {
|
||||||
@ -76,26 +80,24 @@ Text with **bold** & _em_ elements
|
|||||||
syntax={markdownSyntax}
|
syntax={markdownSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Headings', () => {
|
describe('Headings', () => {
|
||||||
for (const heading of [...Array(6).keys()]) {
|
for (const heading of [...Array(6).keys()]) {
|
||||||
it(`should render Heading ${heading + 1}`, () => {
|
it(`should render Heading ${heading + 1}`, () => {
|
||||||
const value = padStart(' Title', heading + 7, '#')
|
const value = padStart(' Title', heading + 7, '#');
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<MarkitupReactRenderer
|
<MarkitupReactRenderer
|
||||||
value={value}
|
value={value}
|
||||||
syntax={markdownSyntax}
|
syntax={markdownSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot()
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('Lists', () => {
|
describe('Lists', () => {
|
||||||
it('should render lists', () => {
|
it('should render lists', () => {
|
||||||
@ -116,8 +118,7 @@ Text with **bold** & _em_ elements
|
|||||||
syntax={markdownSyntax}
|
syntax={markdownSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -136,8 +137,7 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
|
|||||||
syntax={markdownSyntax}
|
syntax={markdownSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,8 +150,7 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
|
|||||||
syntax={markdownSyntax}
|
syntax={markdownSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render code 2', () => {
|
it('should render code 2', () => {
|
||||||
@ -162,8 +161,7 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
|
|||||||
syntax={markdownSyntax}
|
syntax={markdownSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -183,23 +181,50 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
|
|||||||
syntax={markdownSyntax}
|
syntax={markdownSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('custom elements', () => {
|
describe('custom elements', () => {
|
||||||
it('should support custom syntax', () => {
|
it('should extend default renderers with custom ones', () => {
|
||||||
const value = '';
|
const myRule = MarkupIt.Rule('mediaproxy')
|
||||||
|
.regExp(reInline.link, (state, match) => {
|
||||||
|
if (match[0].charAt(0) !== '!') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: Map({
|
||||||
|
alt: match[1],
|
||||||
|
src: match[2],
|
||||||
|
title: match[3]
|
||||||
|
}).filter(Boolean)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const myCustomSchema = {
|
||||||
|
'mediaproxy': (token) => {
|
||||||
|
const src = token.getIn(['data', 'src']);
|
||||||
|
const alt = token.getIn(['data', 'alt']);
|
||||||
|
return <img src={src} alt={alt}/>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const myMarkdownSyntax = markdownSyntax.addInlineRules(myRule);
|
||||||
|
const value = `
|
||||||
|
## Title
|
||||||
|
|
||||||
|

|
||||||
|
`;
|
||||||
const component = shallow(
|
const component = shallow(
|
||||||
<MarkitupReactRenderer
|
<MarkitupReactRenderer
|
||||||
value={value}
|
value={value}
|
||||||
syntax={markdownSyntax}
|
syntax={myMarkdownSyntax}
|
||||||
|
schema={myCustomSchema}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -212,8 +237,7 @@ I get 10 times more traffic from [Google] [1] than from [Yahoo] [2] or [MSN] [3]
|
|||||||
syntax={htmlSyntax}
|
syntax={htmlSyntax}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const tree = component.html();
|
expect(component.html()).toMatchSnapshot();
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -24,8 +24,4 @@ exports[`MarkitupReactRenderer Markdown rendering Links should render links 1`]
|
|||||||
|
|
||||||
exports[`MarkitupReactRenderer Markdown rendering Lists should render lists 1`] = `"<article><ol><li>ol item 1</li><li>ol item 2<ul><li>Sublist 1</li><li>Sublist 2</li><li>Sublist 3<ol><li>Sub-Sublist 1</li><li>Sub-Sublist 2</li><li>Sub-Sublist 3</li></ol></li></ul></li><li>ol item 3</li></ol></article>"`;
|
exports[`MarkitupReactRenderer Markdown rendering Lists should render lists 1`] = `"<article><ol><li>ol item 1</li><li>ol item 2<ul><li>Sublist 1</li><li>Sublist 2</li><li>Sublist 3<ol><li>Sub-Sublist 1</li><li>Sub-Sublist 2</li><li>Sub-Sublist 3</li></ol></li></ul></li><li>ol item 3</li></ol></article>"`;
|
||||||
|
|
||||||
exports[`MarkitupReactRenderer custom elements should extend default renderers with custom ones 1`] = `"<article><p></p></article>"`;
|
exports[`MarkitupReactRenderer custom elements should extend default renderers with custom ones 1`] = `"<article><h2>Title</h2><p><img src=\"http://url.to.image\" alt=\"mediaproxy test\"/></p></article>"`;
|
||||||
|
|
||||||
exports[`MarkitupReactRenderer custom elements should support custom syntax 1`] = `"<article></article>"`;
|
|
||||||
|
|
||||||
exports[`MarkitupReactRenderer custom elements should support custom syntaxes 1`] = `"<article><p></p></article>"`;
|
|
||||||
|
Reference in New Issue
Block a user