diff --git a/src/index.js b/src/index.js
index 9829a68..de42974 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,6 +2,7 @@ import Editor from './components/Editor';
import Toolbar from './components/Toolbar';
import KeyCommandController from './components/KeyCommandController';
import createPlugin from './plugins/createPlugin';
+import accumulatePluginOptions from './plugins/accumulatePluginOptions';
import pluginUtils from './plugins/utils';
import compose from './util/compose';
@@ -10,6 +11,7 @@ export {
Toolbar,
KeyCommandController,
createPlugin,
+ accumulatePluginOptions,
pluginUtils,
- compose
+ compose,
};
diff --git a/src/plugins/accumulatePluginOptions.js b/src/plugins/accumulatePluginOptions.js
new file mode 100644
index 0000000..368d9fc
--- /dev/null
+++ b/src/plugins/accumulatePluginOptions.js
@@ -0,0 +1,75 @@
+import accumulateFunction from '../util/accumulateFunction';
+import memoize from '../util/memoize';
+
+const emptyFunction = () => {};
+const emptyArray = [];
+const emptyObject = {};
+
+const memoizedAccumulateFunction = memoize(accumulateFunction);
+const memoizedAssign = memoize((...args) => Object.assign({}, ...args));
+const memoizedConcat = memoize((a1, a2) => a1.concat(a2));
+const memoizedCoerceArray = memoize((arg = []) =>
+ Array.isArray(arg) ? arg : [arg]
+);
+
+export default (accumulation, pluginConfig) => {
+ const accumulationWithDefaults = {
+ styleMap: emptyObject,
+ styleFn: emptyFunction,
+ decorators: emptyArray,
+ buttons: emptyArray,
+ overlays: emptyArray,
+ blockRendererFn: emptyFunction,
+ blockStyleFn: emptyFunction,
+ keyBindingFn: emptyFunction,
+ keyCommandListeners: emptyArray,
+ ...accumulation,
+ };
+
+ const {
+ styleMap,
+ styleFn,
+ decorators,
+ buttons,
+ overlays,
+ blockRendererFn,
+ blockStyleFn,
+ keyBindingFn,
+ keyCommandListener,
+ } = pluginConfig;
+
+ const keyCommandListeners = memoizedConcat(
+ accumulationWithDefaults.keyCommandListeners,
+ memoizedCoerceArray(keyCommandListener)
+ );
+
+ return {
+ ...accumulationWithDefaults,
+ styleMap: memoizedAssign(accumulationWithDefaults.styleMap, styleMap),
+ styleFn: memoizedAccumulateFunction(
+ accumulationWithDefaults.styleFn,
+ styleFn
+ ),
+ decorators: memoizedConcat(accumulationWithDefaults.decorators, decorators),
+ buttons: memoizedConcat(accumulationWithDefaults.buttons, buttons),
+ overlays: memoizedConcat(accumulationWithDefaults.overlays, overlays),
+ blockRendererFn: memoizedAccumulateFunction(
+ blockRendererFn,
+ accumulationWithDefaults.blockRendererFn
+ ),
+ blockStyleFn: memoizedAccumulateFunction(
+ blockStyleFn,
+ accumulationWithDefaults.blockStyleFn
+ ),
+ keyBindingFn: memoizedAccumulateFunction(
+ keyBindingFn,
+ accumulationWithDefaults.keyBindingFn
+ ),
+
+ // `createPlugin` expects a singular `keyCommandListener`, but Editor
+ // component props expect the plural `keyCommandListeners`, so return both
+ // since this is used in both contexts
+ keyCommandListeners,
+ keyCommandListener: keyCommandListeners,
+ };
+};
diff --git a/src/plugins/createPlugin.js b/src/plugins/createPlugin.js
index 0dee549..40c68ab 100644
--- a/src/plugins/createPlugin.js
+++ b/src/plugins/createPlugin.js
@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
import { OrderedSet } from 'immutable';
import memoize from '../util/memoize';
import compose from '../util/compose';
-import accumulateFunction from '../util/accumulateFunction';
import middlewareAdapter from '../util/middlewareAdapter';
+import accumulatePluginOptions from './accumulatePluginOptions';
const emptyFunction = () => {};
const emptyArray = [];
@@ -14,9 +14,6 @@ const defaultMiddlewareFunction = next => (...args) => next(...args);
defaultMiddlewareFunction.__isMiddleware = true;
const memoizedCompose = memoize(compose);
-const memoizedAccumulateFunction = memoize(accumulateFunction);
-const memoizedAssign = memoize((...args) => Object.assign({}, ...args));
-const memoizedConcat = memoize((a1, a2) => a1.concat(a2));
const memoizedCoerceArray = memoize(arg => (Array.isArray(arg) ? arg : [arg]));
const memoizedPassEmptyStyles = memoize(func => (nodeName, node) =>
func(nodeName, node, OrderedSet())
@@ -73,46 +70,39 @@ const createPlugin = ({
}
render() {
- const newStyleMap = memoizedAssign(this.props.styleMap, styleMap);
- const newStyleFn = memoizedAccumulateFunction(
- this.props.styleFn,
- styleFn
- );
- const newDecorators = memoizedConcat(this.props.decorators, decorators);
- const newButtons = memoizedConcat(this.props.buttons, buttons);
- const newOverlays = memoizedConcat(this.props.overlays, overlays);
- const newBlockRendererFn = memoizedAccumulateFunction(
- blockRendererFn,
- this.props.blockRendererFn
- );
- const newBlockStyleFn = memoizedAccumulateFunction(
- blockStyleFn,
- this.props.blockStyleFn
- );
- const newKeyBindingFn = memoizedAccumulateFunction(
- keyBindingFn,
- this.props.keyBindingFn
- );
- const newKeyCommandListeners = memoizedConcat(
- this.props.keyCommandListeners,
- memoizedCoerceArray(keyCommandListener)
+ const pluginAccumulation = accumulatePluginOptions(
+ {
+ styleMap: this.props.styleMap,
+ styleFn: this.props.styleFn,
+ decorators: this.props.decorators,
+ buttons: this.props.buttons,
+ overlays: this.props.overlays,
+ blockRendererFn: this.props.blockRendererFn,
+ blockStyleFn: this.props.blockStyleFn,
+ keyBindingFn: this.props.keyBindingFn,
+ keyCommandListeners: this.props.keyCommandListeners,
+ },
+ {
+ styleMap,
+ styleFn,
+ decorators,
+ buttons,
+ overlays,
+ blockRendererFn,
+ blockStyleFn,
+ keyBindingFn,
+ keyCommandListener,
+ }
);
- return (
-
- );
+ // keyCommandListener isn't used by the Editor component or other plugin
+ // HOCs but keyCommandListeners is
+ const {
+ __keyCommandListener,
+ ...editorPluginOptions
+ } = pluginAccumulation;
+
+ return ;
}
}
@@ -143,6 +133,18 @@ const createPlugin = ({
};
return Plugin;
+ } else if (ToWrap && ToWrap.__isAccumulator) {
+ return accumulatePluginOptions(ToWrap, {
+ styleMap,
+ styleFn,
+ decorators,
+ buttons,
+ overlays,
+ blockRendererFn,
+ blockStyleFn,
+ keyBindingFn,
+ keyCommandListener,
+ });
} else {
// wrapping a converter function
return (...args) => {
diff --git a/src/util/accumulateFunction.js b/src/util/accumulateFunction.js
index 021321c..f694135 100644
--- a/src/util/accumulateFunction.js
+++ b/src/util/accumulateFunction.js
@@ -1,9 +1,16 @@
// utility function to accumulate the common plugin option function pattern of
// handling args by returning a non-null result or delegate to other plugins
-export default (newFn, acc) => (...args) => {
- const result = newFn(...args);
- if (result === null || result === undefined) {
- return acc(...args);
+const emptyFunction = () => {};
+export default (newFn, acc = emptyFunction) => {
+ if (!newFn) {
+ return acc;
}
- return result;
+
+ return (...args) => {
+ const result = newFn(...args);
+ if (result === null || result === undefined) {
+ return acc(...args);
+ }
+ return result;
+ };
};