diff --git a/src/extend/PluginContext.js b/src/extend/PluginContext.js deleted file mode 100644 index 1c138010ea836aae74d08404f28147afcd70bbed..0000000000000000000000000000000000000000 --- a/src/extend/PluginContext.js +++ /dev/null @@ -1,5 +0,0 @@ -import React from 'react'; - -const PluginContext = React.createContext(); - -export default PluginContext; diff --git a/src/extend/PluginProvider.js b/src/extend/PluginProvider.js deleted file mode 100644 index e3c62358d03606d9fd452d9f06813834eabea943..0000000000000000000000000000000000000000 --- a/src/extend/PluginProvider.js +++ /dev/null @@ -1,42 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; -import { ReactReduxContext } from 'react-redux'; -import PluginContext from './PluginContext'; -import { - filterValidPlugins, - addPluginReducersToStore, - connectPluginsToStore, - createTargetToPluginMapping, -} from './pluginPreprocessing'; - -/** */ -export default function PluginProvider(props) { - const { store } = useContext(ReactReduxContext); - const { plugins, createRootReducer, children } = props; - const [pluginMap, setPluginMap] = useState({}); - - useEffect(() => { - const validPlugins = filterValidPlugins(plugins); - const connectedPlugins = connectPluginsToStore(validPlugins); - createRootReducer && addPluginReducersToStore(store, createRootReducer, validPlugins); - setPluginMap(createTargetToPluginMapping(connectedPlugins)); - }, []); - - return ( - <PluginContext.Provider value={pluginMap}> - { children } - </PluginContext.Provider> - ); -} - -PluginProvider.propTypes = { - children: PropTypes.node, - createRootReducer: PropTypes.func, - plugins: PropTypes.array, // eslint-disable-line react/forbid-prop-types -}; - -PluginProvider.defaultProps = { - children: null, - createRootReducer: null, - plugins: [], -}; diff --git a/src/extend/pluginPreprocessing.js b/src/extend/pluginStore.js similarity index 61% rename from src/extend/pluginPreprocessing.js rename to src/extend/pluginStore.js index 77ac16ad4bec31f98ceb5d4419328342055d029a..292f33b3ef165ed01440ad5c892d5f065d307e9b 100644 --- a/src/extend/pluginPreprocessing.js +++ b/src/extend/pluginStore.js @@ -1,45 +1,25 @@ import update from 'lodash/update'; -import { connect } from 'react-redux'; import { validatePlugin } from './pluginValidation'; -/** - * Returns a mapping from targets to plugins and modes - * - * @param {Array} plugins - * @return {Object} - looks like: - * - * { - * 'WorkspacePanel': { - * wrap: [plugin3, ...], - * add: [plugin4, ...], - * }, - * ... - * } - */ -export function createTargetToPluginMapping(plugins) { - return plugins.reduce((map, plugin) => ( - update(map, [plugin.target, plugin.mode], x => [...x || [], plugin]) - ), {}); -} + +let pluginMap = {}; /** */ -export function filterValidPlugins(plugins) { - const { validPlugins, invalidPlugins } = splitPluginsByValidation(plugins); - logInvalidPlugins(invalidPlugins); - return validPlugins; +export function getPlugins(targetName) { + return pluginMap[targetName]; } /** */ -export function connectPluginsToStore(plugins) { - return plugins.map(plugin => ( - { ...plugin, component: connectPluginComponent(plugin) } - )); +export function storePlugins(plugins = []) { + const validPlugins = filterValidPlugins(plugins); + pluginMap = createTargetToPluginMapping(validPlugins); } /** */ -export function addPluginReducersToStore(store, createRootReducer, plugins) { - const pluginReducers = getReducersFromPlugins(plugins); - store.replaceReducer(createRootReducer(pluginReducers)); +function filterValidPlugins(plugins) { + const { validPlugins, invalidPlugins } = splitPluginsByValidation(plugins); + logInvalidPlugins(invalidPlugins); + return validPlugins; } /** */ @@ -60,12 +40,22 @@ function logInvalidPlugins(plugins) { )); } -/** Connect plugin component to state */ -function connectPluginComponent(plugin) { - return connect(plugin.mapStateToProps, plugin.mapDispatchToProps)(plugin.component); -} - -/** */ -function getReducersFromPlugins(plugins) { - return plugins && plugins.reduce((acc, plugin) => ({ ...acc, ...plugin.reducers }), {}); +/** + * Returns a mapping from targets to plugins and modes + * + * @param {Array} plugins + * @return {Object} - looks like: + * + * { + * 'WorkspacePanel': { + * wrap: [plugin3, ...], + * add: [plugin4, ...], + * }, + * ... + * } + */ +export function createTargetToPluginMapping(plugins) { + return plugins.reduce((map, plugin) => ( + update(map, [plugin.target, plugin.mode], x => [...x || [], plugin]) + ), {}); } diff --git a/src/extend/withPlugins.js b/src/extend/withPlugins.js index cd81be98866446e09030326a2e41d8e8d4b23c5a..861457651b2ff7f2e4cd341dba900d5379691242 100644 --- a/src/extend/withPlugins.js +++ b/src/extend/withPlugins.js @@ -1,34 +1,44 @@ -import React, { useContext } from 'react'; +import React from 'react'; +import { connect } from 'react-redux'; import curry from 'lodash/curry'; import isEmpty from 'lodash/isEmpty'; -import PluginContext from './PluginContext'; +import { getPlugins } from './pluginStore'; - -/** withPlugins should be the innermost HOC */ +/** */ function _withPlugins(targetName, TargetComponent) { // eslint-disable-line no-underscore-dangle - /** */ - function PluginHoc(props) { - const pluginMap = useContext(PluginContext); - const plugins = pluginMap[targetName]; - - if (isEmpty(plugins)) { - return <TargetComponent {...props} />; - } - - if (!isEmpty(plugins.wrap)) { - const PluginComponent = plugins.wrap[0].component; - return <PluginComponent targetProps={props} TargetComponent={TargetComponent} />; - } + let PluginHoc; + const plugins = getPlugins(targetName); - if (!isEmpty(plugins.add)) { - const PluginComponents = plugins.add.map(plugin => plugin.component); - return <TargetComponent {...props} PluginComponents={PluginComponents} />; - } + if (isEmpty(plugins)) { + return TargetComponent; + } + if (!isEmpty(plugins.wrap)) { + PluginHoc = createWrapPluginHoc(plugins, TargetComponent); + } + if (!isEmpty(plugins.add)) { + PluginHoc = createAddPluginHoc(plugins, TargetComponent); } PluginHoc.displayName = `WithPlugins(${targetName})`; return PluginHoc; } +/** */ +function createWrapPluginHoc(plugins, TargetComponent) { + const PluginComponent = connectPluginComponent(plugins[0]); + return props => <PluginComponent targetProps={props} TargetComponent={TargetComponent} />; +} + +/** */ +function createAddPluginHoc(plugins, TargetComponent) { + const PluginComponents = plugins.map(connectPluginComponent); + return props => <TargetComponent {...props} PluginComponents={PluginComponents} />; +} + +/** */ +function connectPluginComponent(plugin) { + return connect(plugin.mapStateToProps, plugin.mapDispatchToProps)(plugin.component); +} + /** withPlugins('MyComponent')(MyComponent) */ export const withPlugins = curry(_withPlugins); diff --git a/src/lib/MiradorViewer.js b/src/lib/MiradorViewer.js index 815405bb333a5b8174b6190153b4c387e1842b6f..02b7dd6e332b4939f26509d6e901276d297fe076 100644 --- a/src/lib/MiradorViewer.js +++ b/src/lib/MiradorViewer.js @@ -2,12 +2,11 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import deepmerge from 'deepmerge'; -import PluginProvider from '../extend/PluginProvider'; -import App from '../containers/App'; +import { storePlugins } from '../extend/pluginStore'; import createStore from '../state/createStore'; -import createRootReducer from '../state/reducers/rootReducer'; import * as actions from '../state/actions'; import settings from '../config/settings'; +import App from '../containers/App'; /** * Default Mirador instantiation @@ -16,7 +15,9 @@ class MiradorViewer { /** */ constructor(config, plugins) { - this.store = createStore(); + storePlugins(plugins); + const pluginReducers = getReducersFromPlugins(plugins); + this.store = createStore(pluginReducers); this.config = config; this.processConfig(); const viewer = { @@ -26,9 +27,7 @@ class MiradorViewer { ReactDOM.render( <Provider store={this.store}> - <PluginProvider plugins={plugins} createRootReducer={createRootReducer}> - <App /> - </PluginProvider> + <App /> </Provider>, document.getElementById(config.id), ); @@ -74,4 +73,9 @@ class MiradorViewer { } } +/** Return reducers from plugins */ +function getReducersFromPlugins(plugins) { + return plugins && plugins.reduce((acc, plugin) => ({ ...acc, ...plugin.reducers }), {}); +} + export default MiradorViewer;