diff --git a/README.md b/README.md index c87e1c7..5073f8f 100644 --- a/README.md +++ b/README.md @@ -10,36 +10,29 @@ npm install --save react-remarkable ## Usage ```jsx +import React from 'react'; +import Markdown from 'react-remarkable'; +import Emoji from 'remarkable-emoji' -var React = require('react'); -var Markdown = require('react-remarkable'); +const MyComponent = () => ( +
+ {/* Pass Markdown source to the `source` prop */} + -var MyComponent = React.createClass({ + {/* Or pass it as children */} + {/* You can nest React components, too */} + {` + ## Reasons React is great - render() { - return ( -
- {/* Pass Markdown source to the `source` prop */} - + 1. Server-side rendering + 2. This totally works: - {/* Or pass it as children */} - {/* You can nest React components, too */} - {` - ## Reasons React is great - - 1. Server-side rendering - 2. This totally works: - - - - Pretty neat! - `} -
- ); - } - -}); + + Pretty neat! + `}
+
+); ``` Available props: @@ -47,6 +40,7 @@ Available props: - `options` - Hash of Remarkable options - `source` - Markdown source. You can also pass the source as children, which allows you to mix React components and Markdown. - `container` - Element to use as container. Defaults to `div`. +- `plugins` - Array of remarkable plugins ## Syntax Highlighting diff --git a/package.json b/package.json index 02c890a..38e6b67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-remarkable", - "version": "1.1.2", + "version": "1.1.3-alpha.2", "description": "A React component for rendering Markdown with remarkable", "main": "dist/index.js", "repository": { diff --git a/src/index.js b/src/index.js index 46c7336..405378e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,34 +1,70 @@ 'use strict'; import React from 'react'; +import PropTypes from 'prop-types'; import Markdown from 'remarkable'; class Remarkable extends React.Component { + static propTypes = { + container: PropTypes.string, + options: PropTypes.object, + source: PropTypes.string, + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]) + } + + static defaultProps = { + container: 'div', + options: {} + } render() { - var Container = this.props.container; + var { + container: Container, + children, options, source, // ⬅ remove Remarkable props + ...props // ⬅ only pass non-Remarkable props + } = this.props; return ( - + {this.content()} ); } + shouldComponentUpdate(nextProps, nextState) { + if (nextProps.options !== this.props.options) { + return true; + } + else if (this.props.source) { + return this.props.source !== nextProps.source; + } + else if (React.Children.count(this.props.children) === 1 && React.Children.count(nextProps.children) === 1) { + return (typeof this.props.children === 'string') && this.props.children !== nextProps.children; + } + else { + return true; + } + } + componentWillUpdate(nextProps, nextState) { if (nextProps.options !== this.props.options) { - this.md = new Markdown(nextProps.options); + this.md = this.createMarkdown(nextProps.options, nextProps.plugins); } } content() { + var Wrapper = this.props.contentWrapper; + if (this.props.source) { - return ; + return ; } else { return React.Children.map(this.props.children, child => { if (typeof child === 'string') { - return ; + return ; } else { return child; @@ -39,16 +75,24 @@ class Remarkable extends React.Component { renderMarkdown(source) { if (!this.md) { - this.md = new Markdown(this.props.options); + this.md = this.createMarkdown(this.props.options, this.props.plugins); } return this.md.render(source); } + + createMarkdown(options, plugins) { + return plugins.reduce((md, plugin) => { + return md.use(plugin); + }, new Markdown(options)); + } } Remarkable.defaultProps = { container: 'div', + contentWrapper: 'span', options: {}, + plugins: [], }; export default Remarkable;