From c21d71f9bcffc03d1021b98dd15ac392ff283874 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Thu, 9 Jun 2016 15:28:44 -0700 Subject: [PATCH 01/13] Add propTypes --- src/index.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/index.js b/src/index.js index 46c7336..7826ae9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,21 @@ '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.array + } + + static defaultProps = { + container: 'div', + options: {} + } render() { var Container = this.props.container; From d91820931f42a6d56423970b359513b11f333110 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Thu, 9 Jun 2016 15:50:31 -0700 Subject: [PATCH 02/13] Don't update the component if the source has not changed If there are no children, then the output could not have changed in this case. --- src/index.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/index.js b/src/index.js index 7826ae9..6a7e838 100644 --- a/src/index.js +++ b/src/index.js @@ -27,6 +27,18 @@ class Remarkable extends React.Component { ); } + shouldComponentUpdate(nextProps, nextState) { + if (nextProps.options !== this.props.options) { + return true; + } + else if (this.props.source) { + return this.props.source !== nextProps.source; + } + else { + return true; + } + } + componentWillUpdate(nextProps, nextState) { if (nextProps.options !== this.props.options) { this.md = new Markdown(nextProps.options); From 1214e3c1aa937aed6fdbef680e9f029b33c83d52 Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Thu, 9 Jun 2016 16:00:47 -0700 Subject: [PATCH 03/13] Also don't update if there is one unchanged string child This case is equivalent to the unchanged source case. --- src/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index.js b/src/index.js index 6a7e838..589a3af 100644 --- a/src/index.js +++ b/src/index.js @@ -34,6 +34,9 @@ class Remarkable extends React.Component { 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; } From 8259b974c314505ac654d993a09176fc27188e4a Mon Sep 17 00:00:00 2001 From: Ben Woosley Date: Tue, 26 Sep 2017 14:32:10 -0700 Subject: [PATCH 04/13] Expand children propTypes to support single children --- src/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 589a3af..3e4bca9 100644 --- a/src/index.js +++ b/src/index.js @@ -9,7 +9,10 @@ class Remarkable extends React.Component { container: PropTypes.string, options: PropTypes.object, source: PropTypes.string, - children: PropTypes.array + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]) } static defaultProps = { From d3d4b4bbcbdc2c28de9641ab2f694ee706a6af54 Mon Sep 17 00:00:00 2001 From: satahippy Date: Wed, 11 Oct 2017 13:41:02 +0300 Subject: [PATCH 05/13] Add remarkable plugins support --- README.md | 4 +++- src/index.js | 11 +++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c87e1c7..607d066 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ npm install --save react-remarkable var React = require('react'); var Markdown = require('react-remarkable'); +var Emoji = require('remarkable-emoji'); var MyComponent = React.createClass({ @@ -20,7 +21,7 @@ var MyComponent = React.createClass({ return (
{/* Pass Markdown source to the `source` prop */} - + {/* Or pass it as children */} {/* You can nest React components, too */} @@ -47,6 +48,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/src/index.js b/src/index.js index 46c7336..4a128b9 100644 --- a/src/index.js +++ b/src/index.js @@ -17,7 +17,7 @@ class Remarkable extends React.Component { componentWillUpdate(nextProps, nextState) { if (nextProps.options !== this.props.options) { - this.md = new Markdown(nextProps.options); + this.md = this.createMarkdown(nextProps.options, nextProps.plugins); } } @@ -39,16 +39,23 @@ 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', options: {}, + plugins: [], }; export default Remarkable; From 987012369daa4dbe053e9da53b79f3ebb9d6d46c Mon Sep 17 00:00:00 2001 From: David Owens Date: Sun, 5 Nov 2017 19:17:20 +0100 Subject: [PATCH 06/13] Use contentWrapper prop to define the wrapper for the parsed content following from https://github.com/acdlite/react-remarkable/issues/24 https://github.com/acdlite/react-remarkable/pull/25 --- src/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 46c7336..9573566 100644 --- a/src/index.js +++ b/src/index.js @@ -22,13 +22,15 @@ class Remarkable extends React.Component { } 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; @@ -48,6 +50,7 @@ class Remarkable extends React.Component { Remarkable.defaultProps = { container: 'div', + contentWrapper: 'span', options: {}, }; From d8885eff1d3e8637346b4860b4941f94301d2888 Mon Sep 17 00:00:00 2001 From: Beau Smith Date: Thu, 5 Apr 2018 11:14:39 -0700 Subject: [PATCH 07/13] Declare propTypes after component. --- src/index.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/index.js b/src/index.js index 3e4bca9..5f14a3d 100644 --- a/src/index.js +++ b/src/index.js @@ -5,20 +5,6 @@ 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; @@ -76,6 +62,16 @@ class Remarkable extends React.Component { } } +Remarkable.propTypes = { + container: PropTypes.string, + options: PropTypes.object, + source: PropTypes.string, + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node, + ]) +}; + Remarkable.defaultProps = { container: 'div', options: {}, From 710568611e4b7b703cc219adaeae23d4909fa3e1 Mon Sep 17 00:00:00 2001 From: Beau Smith Date: Thu, 5 Apr 2018 09:58:46 -0700 Subject: [PATCH 08/13] Pass non-Remarkable props down to the Container. Inspired by: https://github.com/acdlite/react-remarkable/pull/30 --- src/index.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 83c665b..ff44d7b 100644 --- a/src/index.js +++ b/src/index.js @@ -7,10 +7,19 @@ import Markdown from 'remarkable'; class Remarkable extends React.Component { render() { - var Container = this.props.container; + var { + container: Container, + children, + contentWrapper, + options, + plugins, + source, + // ⬆ remove Remarkable props + ...props // ⬅ only pass non-Remarkable props + } = this.props; return ( - + {this.content()} ); @@ -71,13 +80,15 @@ class Remarkable extends React.Component { } Remarkable.propTypes = { - container: PropTypes.string, - options: PropTypes.object, - source: PropTypes.string, children: PropTypes.oneOfType([ PropTypes.arrayOf(PropTypes.node), PropTypes.node, - ]) + ]), + container: PropTypes.string, + contentWrapper: PropTypes.string, + options: PropTypes.object, + plugins: PropTypes.arrayOf(PropTypes.string), + source: PropTypes.string, }; Remarkable.defaultProps = { From 2162c20067c722059b64364c3d731678fe3c1be7 Mon Sep 17 00:00:00 2001 From: captDaylight Date: Wed, 17 Jan 2018 17:37:18 -0500 Subject: [PATCH 09/13] Readme code facelift. Use ES6. --- README.md | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 607d066..830e75e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ react-remarkable -================= +================ A React component for rendering Markdown with [remarkable](https://github.com/jonschlinkert/remarkable). @@ -10,37 +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'); -var Emoji = require('remarkable-emoji'); +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: From 80dd7fb049f8eded012f1aadda7ffd58504dc2aa Mon Sep 17 00:00:00 2001 From: Beau Smith Date: Thu, 5 Apr 2018 12:03:57 -0700 Subject: [PATCH 10/13] Bump to v1.1.3-alpha.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02c890a..cd9eca4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-remarkable", - "version": "1.1.2", + "version": "1.1.3-alpha.3", "description": "A React component for rendering Markdown with remarkable", "main": "dist/index.js", "repository": { From 311b46ed713891e4e97c584646c5dc0c58832266 Mon Sep 17 00:00:00 2001 From: Beau Smith Date: Thu, 5 Apr 2018 16:11:00 -0700 Subject: [PATCH 11/13] Only one "Container" element is necessary. - Merge content method into render method. - Move sort methods to be ordered: lifecycle, custom, then render. --- src/index.js | 88 +++++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/src/index.js b/src/index.js index ff44d7b..941b7bc 100644 --- a/src/index.js +++ b/src/index.js @@ -6,23 +6,10 @@ import Markdown from 'remarkable'; class Remarkable extends React.Component { - render() { - var { - container: Container, - children, - contentWrapper, - options, - plugins, - source, - // ⬆ remove Remarkable props - ...props // ⬅ only pass non-Remarkable props - } = this.props; - - return ( - - {this.content()} - - ); + componentWillUpdate(nextProps, nextState) { + if (nextProps.options !== this.props.options) { + this.md = this.createMarkdown(nextProps.options, nextProps.plugins); + } } shouldComponentUpdate(nextProps, nextState) { @@ -40,30 +27,6 @@ class Remarkable extends React.Component { } } - componentWillUpdate(nextProps, nextState) { - if (nextProps.options !== this.props.options) { - this.md = this.createMarkdown(nextProps.options, nextProps.plugins); - } - } - - content() { - var Wrapper = this.props.contentWrapper; - - if (this.props.source) { - return ; - } - else { - return React.Children.map(this.props.children, child => { - if (typeof child === 'string') { - return ; - } - else { - return child; - } - }); - } - } - renderMarkdown(source) { if (!this.md) { this.md = this.createMarkdown(this.props.options, this.props.plugins); @@ -77,6 +40,47 @@ class Remarkable extends React.Component { return md.use(plugin); }, new Markdown(options)); } + + render() { + var { + container: Container, + children, + options, + plugins, + source, + // ⬆ remove Remarkable props + ...props // ⬅ only pass non-Remarkable props + } = this.props; + + if (!children && !source) { + return null; + } + + if (children) { + return React.Children.map(children, child => { + if (typeof child === 'string') { + return ( + + ); + } + return child; + }); + } + + return ( + + ); + } } Remarkable.propTypes = { @@ -85,7 +89,6 @@ Remarkable.propTypes = { PropTypes.node, ]), container: PropTypes.string, - contentWrapper: PropTypes.string, options: PropTypes.object, plugins: PropTypes.arrayOf(PropTypes.string), source: PropTypes.string, @@ -93,7 +96,6 @@ Remarkable.propTypes = { Remarkable.defaultProps = { container: 'div', - contentWrapper: 'span', options: {}, plugins: [], }; From 9f8226d749130390133a45e4457ec42c084fec2c Mon Sep 17 00:00:00 2001 From: Beau Smith Date: Thu, 5 Apr 2018 16:40:57 -0700 Subject: [PATCH 12/13] Bump version to v1.1.3-alpha.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cd9eca4..ddc5d3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-remarkable", - "version": "1.1.3-alpha.3", + "version": "1.1.3-alpha.4", "description": "A React component for rendering Markdown with remarkable", "main": "dist/index.js", "repository": { From 9549e776136096b827f3a0823329ad997416e364 Mon Sep 17 00:00:00 2001 From: Beau Smith Date: Thu, 5 Apr 2018 16:41:29 -0700 Subject: [PATCH 13/13] Adding dist - because I'm a NPM noob. --- dist/index.js | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 dist/index.js diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..2001c61 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,138 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + +function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _propTypes = require('prop-types'); + +var _propTypes2 = _interopRequireDefault(_propTypes); + +var _remarkable = require('remarkable'); + +var _remarkable2 = _interopRequireDefault(_remarkable); + +var Remarkable = (function (_React$Component) { + _inherits(Remarkable, _React$Component); + + function Remarkable() { + _classCallCheck(this, Remarkable); + + _get(Object.getPrototypeOf(Remarkable.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(Remarkable, [{ + key: 'componentWillUpdate', + value: function componentWillUpdate(nextProps, nextState) { + if (nextProps.options !== this.props.options) { + this.md = this.createMarkdown(nextProps.options, nextProps.plugins); + } + } + }, { + key: 'shouldComponentUpdate', + value: function shouldComponentUpdate(nextProps, nextState) { + if (nextProps.options !== this.props.options) { + return true; + } else if (this.props.source) { + return this.props.source !== nextProps.source; + } else if (_react2['default'].Children.count(this.props.children) === 1 && _react2['default'].Children.count(nextProps.children) === 1) { + return typeof this.props.children === 'string' && this.props.children !== nextProps.children; + } else { + return true; + } + } + }, { + key: 'renderMarkdown', + value: function renderMarkdown(source) { + if (!this.md) { + this.md = this.createMarkdown(this.props.options, this.props.plugins); + } + + return this.md.render(source); + } + }, { + key: 'createMarkdown', + value: function createMarkdown(options, plugins) { + return plugins.reduce(function (md, plugin) { + return md.use(plugin); + }, new _remarkable2['default'](options)); + } + }, { + key: 'render', + value: function render() { + var _this = this; + + var _props = + // ⬆ remove Remarkable props + // ⬅ only pass non-Remarkable props + this.props; + var Container = _props.container; + var children = _props.children; + var options = _props.options; + var plugins = _props.plugins; + var source = _props.source; + + var props = _objectWithoutProperties(_props, ['container', 'children', 'options', 'plugins', 'source']); + + if (!children && !source) { + return null; + } + + if (children) { + return _react2['default'].Children.map(children, function (child) { + if (typeof child === 'string') { + return _react2['default'].createElement(Container, _extends({}, props, { + dangerouslySetInnerHTML: { + __html: _this.renderMarkdown(child) + } + })); + } + return child; + }); + } + + return _react2['default'].createElement(Container, _extends({}, props, { + dangerouslySetInnerHTML: { + __html: this.renderMarkdown(source) + } + })); + } + }]); + + return Remarkable; +})(_react2['default'].Component); + +Remarkable.propTypes = { + children: _propTypes2['default'].oneOfType([_propTypes2['default'].arrayOf(_propTypes2['default'].node), _propTypes2['default'].node]), + container: _propTypes2['default'].string, + options: _propTypes2['default'].object, + plugins: _propTypes2['default'].arrayOf(_propTypes2['default'].string), + source: _propTypes2['default'].string +}; + +Remarkable.defaultProps = { + container: 'div', + options: {}, + plugins: [] +}; + +exports['default'] = Remarkable; +module.exports = exports['default']; \ No newline at end of file