diff --git a/packages/slate-react/src/components/editor.js b/packages/slate-react/src/components/editor.js index 5988de7e9..ad35733af 100644 --- a/packages/slate-react/src/components/editor.js +++ b/packages/slate-react/src/components/editor.js @@ -219,6 +219,7 @@ class Editor extends React.Component { this.tmp.resolves++ const react = ReactPlugin({ ...this.props, + __editor__: this, value: this.props.value || this.state.value, }) diff --git a/packages/slate-react/src/plugins/debug/debug-mutations.js b/packages/slate-react/src/plugins/debug/debug-mutations.js new file mode 100644 index 000000000..715e1d44c --- /dev/null +++ b/packages/slate-react/src/plugins/debug/debug-mutations.js @@ -0,0 +1,86 @@ +import Debug from 'debug' + +const debug = Debug('slate:mutations') + +/** + * Options for MutationObserver + * + * @type {Object} + */ + +const observeOptions = { + childList: true, + characterData: true, + attributes: true, + subtree: true, + characterDataOldValue: true, +} + +/** + * Properties on a MutationRecord + * + * @type {Object} + */ + +const keys = [ + 'type', + 'oldValue', + 'target', + 'addedNodes', + 'removedNodes', + 'attributeName', + 'attributeNamespace', + 'nextSibling', + 'previousSibling', +] + +/** + * Takes a mutation record and turns it into an Object that is easy to log to + * the console. Notably, it removes `null` and `undefined` values as well as + * values that are a `NodeList` that has no entries. + * + * @param {MutationRecord} mutationRecord + */ + +function normalize(mutationRecord) { + const object = {} + + keys.forEach(key => { + const value = mutationRecord[key] + if (value == null) return + if (value instanceof window.NodeList && value.length === 0) return + object[key] = value + }) + return object +} + +/** + * A plugin that sends short easy to digest debug info about each dom mutation + * to browser. + * + * More information about mutations here: + * + * + * + * + * @param {Object} options + */ + +function DebugMutationsPlugin({ __editor__ }) { + const observer = new window.MutationObserver(flush) + + function flush(mutations) { + const array = Array.from(mutations).map(normalize) + debug(`${array.length} MutationRecord`) + // Used `console` because `debug` was not easy to view succinctly + window.console.log(...array) + } + + // `findDOMNode` does not exist until later so we use `setTimeout` + setTimeout(() => { + const rootEl = __editor__.findDOMNode([]) + observer.observe(rootEl, observeOptions) + }) +} + +export default DebugMutationsPlugin diff --git a/packages/slate-react/src/plugins/react/index.js b/packages/slate-react/src/plugins/react/index.js index 633151c4c..b1a91c3b7 100644 --- a/packages/slate-react/src/plugins/react/index.js +++ b/packages/slate-react/src/plugins/react/index.js @@ -9,6 +9,7 @@ import DOMPlugin from '../dom' import RestoreDOMPlugin from './restore-dom' import DebugEventsPlugin from '../debug/debug-events' import DebugBatchEventsPlugin from '../debug/debug-batch-events' +import DebugMutationsPlugin from '../debug/debug-mutations' import NoopPlugin from '../debug/noop' /** @@ -26,6 +27,9 @@ function ReactPlugin(options = {}) { const debugBatchEventsPlugin = Debug.enabled('slate:batch-events') ? DebugBatchEventsPlugin(options) : null + const debugMutationsPlugin = Debug.enabled('slate:mutations') + ? DebugMutationsPlugin(options) + : null const noopPlugin = Debug.enabled('slate:noop') ? NoopPlugin(options) : null const renderingPlugin = RenderingPlugin(options) const commandsPlugin = CommandsPlugin(options) @@ -47,6 +51,7 @@ function ReactPlugin(options = {}) { return [ debugEventsPlugin, debugBatchEventsPlugin, + debugMutationsPlugin, noopPlugin, domPlugin, restoreDomPlugin,