diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..fe8cd1d --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "react"] +} \ No newline at end of file diff --git a/README.md b/README.md index 26a3afe..7963c35 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,92 @@ -# react-diff +# react-stylable-diff -Highlights differences between two strings, uses the [diff](https://www.npmjs.com/package/diff) module +Output differences between two strings in a stylable form. + +Based on [react-diff](https://www.npmjs.com/package/react-diff). Uses the [diff](https://www.npmjs.com/package/diff) module ## Installation ``` -npm install react-diff +npm install react-stylable-diff +``` + +## Usage + +Pass text to compare as `props.inputA` and `props.inputB`: + +```javascript +var React = require('react'); +var Diff = require('react-stylable-diff'); + +var MyComponent = React.createClass({ + render: function() { + return ( + + ); + } +}); +``` + +You can also specify different values in `props.type` +to compare in different ways. Valid values are `'chars'`, `'words'`, `'wordsWit Space'`, `'lines'`, `'trimmedLines'`, `'sentences'`, `'css'`, and `'json'`. You can also use options (check it in [diff](https://github.com/kpdecker/jsdiff) module): + + +```javascript +var React = require('react'); +var Diff = require('react-stylable-diff'); + +var MyComponent = React.createClass({ + render: function() { + return ( + + ); + } +}); ``` -## Demo +### Styling + +Outputs standard `` and `` tags so you will at least +have the browser default styling for these. On my browser they +appear crossed-out or underlined. + +You will probably want to add your own styles to look all fancy. + +The output is wrapped in a div with class `'Difference'` so you can +attach all your style rules to that. You can override this class with +`props.className` if you like. -http://cezary.github.io/react-diff/ +Here are some styles that might work: + +```css +.Difference { + font-family: monospace; +} + +.Difference > del { + background-color: rgb(255, 224, 224); + text-decoration: none; +} + +.Difference > ins { + background-color: rgb(201, 238, 211); + text-decoration: none; +} +``` ## Example ```javascript var React = require('react'); -var Diff = require('react-diff'); +var Diff = require('react-stylable-diff'); var Component = React.createClass({ render: function() { return ( - + ); } }); diff --git a/dist/react-diff.js b/dist/react-diff.js index 947b6db..c57bf92 100644 --- a/dist/react-diff.js +++ b/dist/react-diff.js @@ -1,48 +1,113 @@ 'use strict'; -var React = require('react'); -var jsdiff = require('diff'); +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; }; }(); + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _react = require('react'); + +var _react2 = _interopRequireDefault(_react); + +var _diff = require('diff'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +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 fnMap = { - chars: jsdiff.diffChars, - words: jsdiff.diffWords, - sentences: jsdiff.diffSentences, - json: jsdiff.diffJson + 'chars': _diff.diffChars, + 'words': _diff.diffWords, + 'wordsWithSpace': _diff.diffWrodsWithSpace, + 'lines': _diff.diffLines, + 'trimmedLines': _diff.diffTrimmedLines, + 'sentences': _diff.diffSentences, + 'css': _diff.diffCss, + 'json': _diff.diffJson }; -module.exports = React.createClass({ - displayName: 'Diff', +/** + * Display diff in a stylable form. + * + * Default is character diff. Change with props.type. Valid values + * are 'chars', 'words', 'sentences', 'json'. + * + * - Wrapping div has class 'Difference', override with props.className + * - added parts are in + * - removed parts are in + * - unchanged parts are in + */ + +var ReactDiff = function (_React$Component) { + _inherits(ReactDiff, _React$Component); + + function ReactDiff() { + _classCallCheck(this, ReactDiff); - getDefaultProps: function getDefaultProps() { - return { + var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(ReactDiff).call(this)); + + _this.displayName = 'Diff'; + + _this.defaultProps = { inputA: '', inputB: '', - type: 'chars' + type: 'chars', + options: null, + className: 'difference' }; - }, - - propTypes: { - inputA: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]), - inputB: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]), - type: React.PropTypes.oneOf(['chars', 'words', 'sentences', 'json']) - }, - - render: function render() { - var diff = fnMap[this.props.type](this.props.inputA, this.props.inputB); - var result = diff.map(function (part) { - var spanStyle = { - backgroundColor: part.added ? 'lightgreen' : part.removed ? 'salmon' : 'lightgrey' - }; - return React.createElement( - 'span', - { style: spanStyle }, - part.value + + _this.propTypes = { + inputA: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.object]), + inputB: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.object]), + type: _react2.default.PropTypes.oneOf(['chars', 'words', 'wordsWithSpace', 'lines', 'trimmedLines', 'sentences', 'css', 'json']), + options: _react2.default.PropTypes.object + }; + return _this; + } + + _createClass(ReactDiff, [{ + key: 'render', + value: function render() { + var diff = fnMap[this.props.type](this.props.inputA, this.props.inputB, this.props.options); + + var result = diff.map(function (part, index) { + if (part.added) { + return _react2.default.createElement( + 'ins', + { key: index }, + part.value + ); + } + if (part.removed) { + return _react2.default.createElement( + 'del', + { key: index }, + part.value + ); + } + return _react2.default.createElement( + 'span', + { key: index }, + part.value + ); + }); + + return _react2.default.createElement( + 'div', + this.props, + result ); - }); - return React.createElement( - 'pre', - { className: 'diff-result' }, - result - ); - } }); + } + }]); + + return ReactDiff; +}(_react2.default.Component); + +exports.default = ReactDiff; +; diff --git a/lib/react-diff.js b/lib/react-diff.js deleted file mode 100644 index 24dad04..0000000 --- a/lib/react-diff.js +++ /dev/null @@ -1,53 +0,0 @@ -var React = require('react'); -var jsdiff = require('diff'); - -var fnMap = { - 'chars': jsdiff.diffChars, - 'words': jsdiff.diffWords, - 'sentences': jsdiff.diffSentences, - 'json': jsdiff.diffJson -}; - -module.exports = React.createClass({ - displayName: 'Diff', - - getDefaultProps: function() { - return { - inputA: '', - inputB: '', - type: 'chars' - }; - }, - - propTypes: { - inputA: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.object - ]), - inputB: React.PropTypes.oneOfType([ - React.PropTypes.string, - React.PropTypes.object - ]), - type: React.PropTypes.oneOf([ - 'chars', - 'words', - 'sentences', - 'json' - ]) - }, - - render: function () { - var diff = fnMap[this.props.type](this.props.inputA, this.props.inputB); - var result = diff.map(function(part, index) { - var spanStyle = { - backgroundColor: part.added ? 'lightgreen' : part.removed ? 'salmon' : 'lightgrey' - } - return {part.value} - }); - return ( -
-        {result}
-      
- ); - }, -}); diff --git a/lib/react-diff.jsx b/lib/react-diff.jsx new file mode 100644 index 0000000..858799e --- /dev/null +++ b/lib/react-diff.jsx @@ -0,0 +1,81 @@ +import React from 'react'; +import {diffChars, diffWords, diffWrodsWithSpace, diffLines, diffTrimmedLines, diffSentences, diffCss, diffJson} from 'diff'; + +var fnMap = { + 'chars': diffChars, + 'words': diffWords, + 'wordsWithSpace': diffWrodsWithSpace, + 'lines': diffLines, + 'trimmedLines': diffTrimmedLines, + 'sentences': diffSentences, + 'css': diffCss, + 'json': diffJson +}; + +/** + * Display diff in a stylable form. + * + * Default is character diff. Change with props.type. Valid values + * are 'chars', 'words', 'sentences', 'json'. + * + * - Wrapping div has class 'Difference', override with props.className + * - added parts are in + * - removed parts are in + * - unchanged parts are in + */ +export default class ReactDiff extends React.Component { + constructor() { + super(); + this.displayName = 'Diff'; + + this.defaultProps = { + inputA: '', + inputB: '', + type: 'chars', + options: null, + className: 'difference' + }; + + this.propTypes = { + inputA: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.object + ]), + inputB: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.object + ]), + type: React.PropTypes.oneOf([ + 'chars', + 'words', + 'wordsWithSpace', + 'lines', + 'trimmedLines', + 'sentences', + 'css', + 'json' + ]), + options: React.PropTypes.object + } + } + + render() { + var diff = fnMap[this.props.type](this.props.inputA, this.props.inputB, this.props.options); + + var result = diff.map(function(part, index) { + if (part.added) { + return {part.value}; + } + if (part.removed) { + return {part.value}; + } + return {part.value}; + }); + + return ( +
+ {result} +
+ ); + } +}; diff --git a/package.json b/package.json index 80d8ade..18bc6d5 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,39 @@ { - "name": "react-diff", - "version": "0.0.6", - "description": "Highlight differences between inputs", + "name": "react-stylable-diff", + "version": "1.0.1", + "description": "Output differences between inputs, ready for css styling", "main": "dist/react-diff.js", "scripts": { - "build": "./node_modules/.bin/babel lib/react-diff.js > dist/react-diff.js" + "build": "babel lib --out-dir dist" }, "repository": { "type": "git", - "url": "https://github.com/cezary/react-diff.git" + "url": "https://github.com/davidmason/react-stylable-diff.git" }, "keywords": [ "react", - "diff" + "diff", + "css" + ], + "author": "David Mason ", + "contributors": [ + "Cezary Wojtkowski ", + "Felix Hao " ], - "author": "Cezary Wojtkowski ", "license": "MIT", "bugs": { - "url": "https://github.com/cezary/react-diff/issues" + "url": "https://github.com/davidmason/react-stylable-diff/issues" }, - "homepage": "https://github.com/cezary/react-diff", + "homepage": "https://github.com/davidmason/react-stylable-diff", "peerDependencies": { "react": ">=0.12.0" }, "dependencies": { - "diff": "^1.2.0" + "diff": "^2.2.1" }, "devDependencies": { - "babel": "^5.1.10" + "babel": "^6.3.26", + "babel-preset-es2015": "^6.3.13", + "babel-preset-react": "^6.3.13" } }