diff --git a/README.md b/README.md index cdde0c4..13ae733 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,11 @@ If you're using Webpack, you're probably excluding `node_modules` from your Babe loaders: ["babel-loader"] } +### Props + +* value - String of inital HTML to edit, see above for currently supported tags +* onChange - function to call onChange, will receive emitted HTML as string +* debounce - debounce delay for emitting html in ms, defaults to 0, improves performance massively when editing large documents ### Demo diff --git a/example-dist/bundle.js b/example-dist/bundle.js new file mode 100644 index 0000000..1463736 --- /dev/null +++ b/example-dist/bundle.js @@ -0,0 +1,2960 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + eval("module.exports = __webpack_require__(1);\n\n\n/*****************\n ** WEBPACK FOOTER\n ** multi example\n ** module id = 0\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///multi_example?"); + +/***/ }, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + eval("'use strict';\n\nvar _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; }; }();\n\nvar _react = __webpack_require__(2);\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _reactDom = __webpack_require__(159);\n\nvar _reactDom2 = _interopRequireDefault(_reactDom);\n\nvar _BasicHtmlEditor = __webpack_require__(160);\n\nvar _BasicHtmlEditor2 = _interopRequireDefault(_BasicHtmlEditor);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _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; }\n\nfunction _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; }\n\nvar html = '\\n
Here\\'s some text, it\\'s useful
\\nMore text, some inline styling for some elements
\\n';\n\nvar BasicHtmlEditorExample = function (_React$Component) {\n _inherits(BasicHtmlEditorExample, _React$Component);\n\n function BasicHtmlEditorExample(props) {\n _classCallCheck(this, BasicHtmlEditorExample);\n\n var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(BasicHtmlEditorExample).call(this, props));\n\n _this.state = {\n html: props.html\n };\n return _this;\n }\n\n _createClass(BasicHtmlEditorExample, [{\n key: 'updateHtml',\n value: function updateHtml(html) {\n this.setState({\n html: html\n });\n }\n }, {\n key: 'render',\n value: function render() {\n var _this2 = this;\n\n return _react2.default.createElement(\n 'div',\n null,\n _react2.default.createElement(_BasicHtmlEditor2.default, {\n value: this.state.html,\n onChange: function onChange(html) {\n return _this2.updateHtml(html);\n },\n debounce: 500\n }),\n _react2.default.createElement(\n 'div',\n { style: { margin: '30px 10px 10px 10px' } },\n _react2.default.createElement(\n 'code',\n null,\n 'Exported HTML'\n ),\n _react2.default.createElement('hr', null),\n _react2.default.createElement('div', { dangerouslySetInnerHTML: { __html: this.state.html } })\n )\n );\n }\n }]);\n\n return BasicHtmlEditorExample;\n}(_react2.default.Component);\n\n_reactDom2.default.render(_react2.default.createElement(BasicHtmlEditorExample, { html: html }), document.getElementById('app'));\n\n/*****************\n ** WEBPACK FOOTER\n ** ./example/index.js\n ** module id = 1\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./example/index.js?"); + +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + eval("'use strict';\n\nmodule.exports = __webpack_require__(3);\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react/react.js\n ** module id = 2\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./~/react/react.js?"); + +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + + eval("/**\n * Copyright 2013-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n *\n * @providesModule React\n */\n\n'use strict';\n\nvar ReactDOM = __webpack_require__(4);\nvar ReactDOMServer = __webpack_require__(149);\nvar ReactIsomorphic = __webpack_require__(153);\n\nvar assign = __webpack_require__(40);\nvar deprecated = __webpack_require__(158);\n\n// `version` will be added here by ReactIsomorphic.\nvar React = {};\n\nassign(React, ReactIsomorphic);\n\nassign(React, {\n // ReactDOM\n findDOMNode: deprecated('findDOMNode', 'ReactDOM', 'react-dom', ReactDOM, ReactDOM.findDOMNode),\n render: deprecated('render', 'ReactDOM', 'react-dom', ReactDOM, ReactDOM.render),\n unmountComponentAtNode: deprecated('unmountComponentAtNode', 'ReactDOM', 'react-dom', ReactDOM, ReactDOM.unmountComponentAtNode),\n\n // ReactDOMServer\n renderToString: deprecated('renderToString', 'ReactDOMServer', 'react-dom/server', ReactDOMServer, ReactDOMServer.renderToString),\n renderToStaticMarkup: deprecated('renderToStaticMarkup', 'ReactDOMServer', 'react-dom/server', ReactDOMServer, ReactDOMServer.renderToStaticMarkup)\n});\n\nReact.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOM;\nReact.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOMServer;\n\nmodule.exports = React;\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react/lib/React.js\n ** module id = 3\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./~/react/lib/React.js?"); + +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { + + eval("/* WEBPACK VAR INJECTION */(function(process) {/**\n * Copyright 2013-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n *\n * @providesModule ReactDOM\n */\n\n/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/\n\n'use strict';\n\nvar ReactCurrentOwner = __webpack_require__(6);\nvar ReactDOMTextComponent = __webpack_require__(7);\nvar ReactDefaultInjection = __webpack_require__(72);\nvar ReactInstanceHandles = __webpack_require__(46);\nvar ReactMount = __webpack_require__(29);\nvar ReactPerf = __webpack_require__(19);\nvar ReactReconciler = __webpack_require__(51);\nvar ReactUpdates = __webpack_require__(55);\nvar ReactVersion = __webpack_require__(147);\n\nvar findDOMNode = __webpack_require__(92);\nvar renderSubtreeIntoContainer = __webpack_require__(148);\nvar warning = __webpack_require__(26);\n\nReactDefaultInjection.inject();\n\nvar render = ReactPerf.measure('React', 'render', ReactMount.render);\n\nvar React = {\n findDOMNode: findDOMNode,\n render: render,\n unmountComponentAtNode: ReactMount.unmountComponentAtNode,\n version: ReactVersion,\n\n /* eslint-disable camelcase */\n unstable_batchedUpdates: ReactUpdates.batchedUpdates,\n unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer\n};\n\n// Inject the runtime into a devtools global hook regardless of browser.\n// Allows for debugging when the hook is injected on the page.\n/* eslint-enable camelcase */\nif (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {\n __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({\n CurrentOwner: ReactCurrentOwner,\n InstanceHandles: ReactInstanceHandles,\n Mount: ReactMount,\n Reconciler: ReactReconciler,\n TextComponent: ReactDOMTextComponent\n });\n}\n\nif (process.env.NODE_ENV !== 'production') {\n var ExecutionEnvironment = __webpack_require__(10);\n if (ExecutionEnvironment.canUseDOM && window.top === window.self) {\n\n // First check if devtools is not installed\n if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {\n // If we're in Chrome or Firefox, provide a download link if not installed.\n if (navigator.userAgent.indexOf('Chrome') > -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) {\n console.debug('Download the React DevTools for a better development experience: ' + 'https://fb.me/react-devtools');\n }\n }\n\n // If we're in IE8, check to see if we are in compatibility mode and provide\n // information on preventing compatibility mode\n var ieCompatibilityMode = document.documentMode && document.documentMode < 8;\n\n process.env.NODE_ENV !== 'production' ? warning(!ieCompatibilityMode, 'Internet Explorer is running in compatibility mode; please add the ' + 'following tag to your HTML to prevent this from happening: ' + '') : undefined;\n\n var expectedFeatures = [\n // shims\n Array.isArray, Array.prototype.every, Array.prototype.forEach, Array.prototype.indexOf, Array.prototype.map, Date.now, Function.prototype.bind, Object.keys, String.prototype.split, String.prototype.trim,\n\n // shams\n Object.create, Object.freeze];\n\n for (var i = 0; i < expectedFeatures.length; i++) {\n if (!expectedFeatures[i]) {\n console.error('One or more ES5 shim/shams expected by React are not available: ' + 'https://fb.me/react-warning-polyfills');\n break;\n }\n }\n }\n}\n\nmodule.exports = React;\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5)))\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react/lib/ReactDOM.js\n ** module id = 4\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./~/react/lib/ReactDOM.js?"); + +/***/ }, +/* 5 */ +/***/ function(module, exports) { + + eval("// shim for using process in browser\n\nvar process = module.exports = {};\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = setTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n clearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n setTimeout(drainQueue, 0);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/process/browser.js\n ** module id = 5\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./~/process/browser.js?"); + +/***/ }, +/* 6 */ +/***/ function(module, exports) { + + eval("/**\n * Copyright 2013-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n *\n * @providesModule ReactCurrentOwner\n */\n\n'use strict';\n\n/**\n * Keeps track of the current owner.\n *\n * The current owner is the component who should own any components that are\n * currently being constructed.\n */\nvar ReactCurrentOwner = {\n\n /**\n * @internal\n * @type {ReactComponent}\n */\n current: null\n\n};\n\nmodule.exports = ReactCurrentOwner;\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react/lib/ReactCurrentOwner.js\n ** module id = 6\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./~/react/lib/ReactCurrentOwner.js?"); + +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { + + eval("/* WEBPACK VAR INJECTION */(function(process) {/**\n * Copyright 2013-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n *\n * @providesModule ReactDOMTextComponent\n * @typechecks static-only\n */\n\n'use strict';\n\nvar DOMChildrenOperations = __webpack_require__(8);\nvar DOMPropertyOperations = __webpack_require__(23);\nvar ReactComponentBrowserEnvironment = __webpack_require__(27);\nvar ReactMount = __webpack_require__(29);\n\nvar assign = __webpack_require__(40);\nvar escapeTextContentForBrowser = __webpack_require__(22);\nvar setTextContent = __webpack_require__(21);\nvar validateDOMNesting = __webpack_require__(71);\n\n/**\n * Text nodes violate a couple assumptions that React makes about components:\n *\n * - When mounting text into the DOM, adjacent text nodes are merged.\n * - Text nodes cannot be assigned a React root ID.\n *\n * This component is used to wrap strings in elements so that they can undergo\n * the same reconciliation that is applied to elements.\n *\n * TODO: Investigate representing React components in the DOM with text nodes.\n *\n * @class ReactDOMTextComponent\n * @extends ReactComponent\n * @internal\n */\nvar ReactDOMTextComponent = function (props) {\n // This constructor and its argument is currently used by mocks.\n};\n\nassign(ReactDOMTextComponent.prototype, {\n\n /**\n * @param {ReactText} text\n * @internal\n */\n construct: function (text) {\n // TODO: This is really a ReactText (ReactNode), not a ReactElement\n this._currentElement = text;\n this._stringText = '' + text;\n\n // Properties\n this._rootNodeID = null;\n this._mountIndex = 0;\n },\n\n /**\n * Creates the markup for this text node. This node is not intended to have\n * any features besides containing text content.\n *\n * @param {string} rootID DOM ID of the root node.\n * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction\n * @return {string} Markup for this text node.\n * @internal\n */\n mountComponent: function (rootID, transaction, context) {\n if (process.env.NODE_ENV !== 'production') {\n if (context[validateDOMNesting.ancestorInfoContextKey]) {\n validateDOMNesting('span', null, context[validateDOMNesting.ancestorInfoContextKey]);\n }\n }\n\n this._rootNodeID = rootID;\n if (transaction.useCreateElement) {\n var ownerDocument = context[ReactMount.ownerDocumentContextKey];\n var el = ownerDocument.createElement('span');\n DOMPropertyOperations.setAttributeForID(el, rootID);\n // Populate node cache\n ReactMount.getID(el);\n setTextContent(el, this._stringText);\n return el;\n } else {\n var escapedText = escapeTextContentForBrowser(this._stringText);\n\n if (transaction.renderToStaticMarkup) {\n // Normally we'd wrap this in a `span` for the reasons stated above, but\n // since this is a situation where React won't take over (static pages),\n // we can simply return the text as it is.\n return escapedText;\n }\n\n return '' + escapedText + '';\n }\n },\n\n /**\n * Updates this component by updating the text content.\n *\n * @param {ReactText} nextText The next text content\n * @param {ReactReconcileTransaction} transaction\n * @internal\n */\n receiveComponent: function (nextText, transaction) {\n if (nextText !== this._currentElement) {\n this._currentElement = nextText;\n var nextStringText = '' + nextText;\n if (nextStringText !== this._stringText) {\n // TODO: Save this as pending props and use performUpdateIfNecessary\n // and/or updateComponent to do the actual update for consistency with\n // other component types?\n this._stringText = nextStringText;\n var node = ReactMount.getNode(this._rootNodeID);\n DOMChildrenOperations.updateTextContent(node, nextStringText);\n }\n }\n },\n\n unmountComponent: function () {\n ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);\n }\n\n});\n\nmodule.exports = ReactDOMTextComponent;\n/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5)))\n\n/*****************\n ** WEBPACK FOOTER\n ** ./~/react/lib/ReactDOMTextComponent.js\n ** module id = 7\n ** module chunks = 0\n **/\n//# sourceURL=webpack:///./~/react/lib/ReactDOMTextComponent.js?"); + +/***/ }, +/* 8 */ +/***/ function(module, exports, __webpack_require__) { + + eval("/* WEBPACK VAR INJECTION */(function(process) {/**\n * Copyright 2013-2015, Facebook, Inc.\n * All rights reserved.\n *\n * This source code is licensed under the BSD-style license found in the\n * LICENSE file in the root directory of this source tree. An additional grant\n * of patent rights can be found in the PATENTS file in the same directory.\n *\n * @providesModule DOMChildrenOperations\n * @typechecks static-only\n */\n\n'use strict';\n\nvar Danger = __webpack_require__(9);\nvar ReactMultiChildUpdateTypes = __webpack_require__(17);\nvar ReactPerf = __webpack_require__(19);\n\nvar setInnerHTML = __webpack_require__(20);\nvar setTextContent = __webpack_require__(21);\nvar invariant = __webpack_require__(14);\n\n/**\n * Inserts `childNode` as a child of `parentNode` at the `index`.\n *\n * @param {DOMElement} parentNode Parent node in which to insert.\n * @param {DOMElement} childNode Child node to insert.\n * @param {number} index Index at which to insert the child.\n * @internal\n */\nfunction insertChildAt(parentNode, childNode, index) {\n // By exploiting arrays returning `undefined` for an undefined index, we can\n // rely exclusively on `insertBefore(node, null)` instead of also using\n // `appendChild(node)`. However, using `undefined` is not allowed by all\n // browsers so we must replace it with `null`.\n\n // fix render order error in safari\n // IE8 will throw error when index out of list size.\n var beforeChild = index >= parentNode.childNodes.length ? null : parentNode.childNodes.item(index);\n\n parentNode.insertBefore(childNode, beforeChild);\n}\n\n/**\n * Operations for updating with DOM children.\n */\nvar DOMChildrenOperations = {\n\n dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,\n\n updateTextContent: setTextContent,\n\n /**\n * Updates a component's children by processing a series of updates. The\n * update configurations are each expected to have a `parentNode` property.\n *\n * @param {array