Skip to content

Commit

Permalink
Add createElement option (#152)
Browse files Browse the repository at this point in the history
* Add temporary Prettier formatting ignore rule

* Add custom render function option

* Add option details to README

* Fix missing render arg

* Add custom rendererer func tests

* Generalize JSX rendering statement

* Fix linting errors
  • Loading branch information
hugmanrique authored and quantizor committed Mar 4, 2018
1 parent 1e3b1d5 commit ac20c7c
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 2 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

<!-- TOC -->

- [Markdown Component for React, Preact + Friends](#markdown-component-for-react-preact--friends)
- [Markdown Component for React, Preact + Friends](#markdown-component-for-react-preact-friends)
- [Installation](#installation)
- [Usage](#usage)
- [Parsing Options](#parsing-options)
- [options.forceBlock](#optionsforceblock)
- [options.forceInline](#optionsforceinline)
- [options.overrides - Override Any HTML Tag's Representation](#optionsoverrides---override-any-html-tags-representation)
- [options.overrides - Rendering Arbitrary React Components](#optionsoverrides---rendering-arbitrary-react-components)
- [options.createElement - Custom React.createElement behavior](#optionscreateelement---custom-reactcreateelement-behavior)
- [Getting the smallest possible bundle size](#getting-the-smallest-possible-bundle-size)
- [Usage with Preact](#usage-with-preact)
- [Using The Compiler Directly](#using-the-compiler-directly)
Expand Down Expand Up @@ -300,6 +301,34 @@ render((
), document.body);
```

#### options.createElement - Custom React.createElement behavior

Sometimes, you might want to override the `React.createElement` default behavior to hook into the rendering process before the JSX gets rendered. This might be useful to add extra children or modify some props based on runtime conditions. The function mirrors the `React.createElement` function, so the params are [`type, [props], [...children]`](https://reactjs.org/docs/react-api.html#createelement):

```javascript
import Markdown from 'markdown-to-jsx';
import React from 'react';
import {render} from 'react-dom';

const md = `
# Hello world
`;

render((
<Markdown
children={md}
options={{
createElement(type, props, children) {
return (
<div className='parent'>
{React.createElement(type, props, children)}
</div>
);
}
}} />
), document.body);
```

### Getting the smallest possible bundle size

Many development conveniences are placed behind `process.env.NODE_ENV !== "production"` conditionals. When bundling your app, it's a good idea to replace these code snippets such that a minifier (like uglify) can sweep them away and leave a smaller overall bundle.
Expand Down
5 changes: 4 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -606,10 +606,13 @@ export function compiler (markdown, options) {
options = options || {};
options.overrides = options.overrides || {};

const createElementFn = options.createElement || React.createElement;

// eslint-disable-next-line no-unused-vars
function h (tag, props, ...children) {
const overrideProps = get(options.overrides, `${tag}.props`, {});
return React.createElement(getTag(tag, options.overrides), {

return createElementFn(getTag(tag, options.overrides), {
...overrideProps,
...props,
className: cx(props && props.className, overrideProps.className) || undefined,
Expand Down
39 changes: 39 additions & 0 deletions index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,45 @@ $25
});
});

describe('options.createElement', () => {
it('should render a <custom> element if render function overrides the element type', () => {
render(
compiler('Hello', {
createElement (type, props, children) {
return React.createElement('custom', props, children);
},
})
);

// The tag name is always in the upper-case form.
// https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName
expect(root.children[0].tagName).toBe('CUSTOM');
});

it('should render an empty <div> element', () => {
render(
compiler('Hello', {
createElement () {
return React.createElement('div');
},
})
);

expect(root.children[0].innerHTML).toBe('');
expect(root.children[0].children.length).toBe(0);
});

it('should throw error if render function returns null', () => {
expect(() => {
render(
compiler('Hello', {
createElement: () => null,
})
);
}).toThrow(/Invalid component element/);
});
});

describe('overrides', () => {
it('should substitute the appropriate JSX tag if given a component', () => {
class FakeParagraph extends React.Component {
Expand Down

0 comments on commit ac20c7c

Please sign in to comment.