From 34c117af91a28d0ff2248c52dcdd3c6d60beff4e Mon Sep 17 00:00:00 2001
From: Jack Reed <phillipjreed@gmail.com>
Date: Mon, 6 Jan 2020 18:14:01 -0700
Subject: [PATCH] Enable both select add components to also be wrappable

---
 .../integration/mirador/plugins/add.html      | 25 +++++++++++++++++--
 .../integration/mirador/plugins/add.test.js   |  6 +++++
 .../mirador/plugins/priority.test.js          |  4 +--
 __tests__/src/extend/withPlugins.test.js      | 25 ++++++++++++++++++-
 src/components/WindowTopBarPluginMenu.js      |  6 +++--
 src/extend/withPlugins.js                     | 13 ++++++++++
 6 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/__tests__/integration/mirador/plugins/add.html b/__tests__/integration/mirador/plugins/add.html
index 651a54eda..cb5bda4e7 100644
--- a/__tests__/integration/mirador/plugins/add.html
+++ b/__tests__/integration/mirador/plugins/add.html
@@ -14,7 +14,7 @@
     <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
     <script type="text/babel">
 
-      const config = { id: 'mirador' };
+      const config = { id: 'mirador', windows: [{manifestId: 'https://purl.stanford.edu/hg676jb4964/iiif/manifest'}] };
 
       const AddPluginComponentA = (props) => (
         <div id="add-plugin-component-a">
@@ -34,6 +34,21 @@
         </div>
       );
 
+      const CustomIcon = () => (
+        <svg className="umbrella" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" aria-labelledby="title">
+	        <title id="title">Umbrella Icon</title>
+          <path d="M27 14h5c0-1.105-1.119-2-2.5-2s-2.5 0.895-2.5 2v0zM27 14c0-1.105-1.119-2-2.5-2s-2.5 0.895-2.5 2c0-1.105-1.119-2-2.5-2s-2.5 0.895-2.5 2v0 14c0 1.112-0.895 2-2 2-1.112 0-2-0.896-2-2.001v-1.494c0-0.291 0.224-0.505 0.5-0.505 0.268 0 0.5 0.226 0.5 0.505v1.505c0 0.547 0.444 0.991 1 0.991 0.552 0 1-0.451 1-0.991v-14.009c0-1.105-1.119-2-2.5-2s-2.5 0.895-2.5 2c0-1.105-1.119-2-2.5-2s-2.5 0.895-2.5 2c0-1.105-1.119-2-2.5-2s-2.5 0.895-2.5 2c0-5.415 6.671-9.825 15-9.995v-1.506c0-0.283 0.224-0.499 0.5-0.499 0.268 0 0.5 0.224 0.5 0.499v1.506c8.329 0.17 15 4.58 15 9.995h-5z"/>
+        </svg>
+      );
+
+      const WrapPluginComponent = (plugin) => {
+        return (
+          <div id='wrapped-plugin-with-adds'>
+            <plugin.TargetComponent menuIcon={<CustomIcon/>} {...plugin.targetProps} {...plugin} />
+          </div>
+        )
+      }
+
       const addPluginA = {
         target: 'WorkspaceControlPanelButtons',
         mode: 'add',
@@ -51,8 +66,14 @@
         mode: 'add',
         component: AddPluginComponentC,
       };
+      
+      const wrapPluginD = {
+        target: 'WindowTopBarPluginMenu',
+        mode: 'wrap',
+        component: WrapPluginComponent,
+      };
 
-      const miradorInstance = Mirador.viewer(config, [addPluginA, addPluginB, addPluginC]);
+      const miradorInstance = Mirador.viewer(config, [addPluginA, addPluginB, addPluginC, wrapPluginD]);
 
      </script>
   </body>
diff --git a/__tests__/integration/mirador/plugins/add.test.js b/__tests__/integration/mirador/plugins/add.test.js
index 3c3550c5f..03889a958 100644
--- a/__tests__/integration/mirador/plugins/add.test.js
+++ b/__tests__/integration/mirador/plugins/add.test.js
@@ -10,4 +10,10 @@ describe('add two plugins to <WorkspaceControlPanelButtons>', () => {
     await expect(page).toMatchElement('#add-plugin-component-a');
     await expect(page).toMatchElement('#add-plugin-component-b');
   });
+
+  it('wrapped and added plugins will be added to <WindowTopBarPluginMenu>', async () => {
+    await expect(page).toClick('#wrapped-plugin-with-adds button');
+    await expect(page).toMatchElement('#add-plugin-component-c');
+    await expect(page).toMatchElement('#wrapped-plugin-with-adds');
+  });
 });
diff --git a/__tests__/integration/mirador/plugins/priority.test.js b/__tests__/integration/mirador/plugins/priority.test.js
index ecd275051..3f069fa72 100644
--- a/__tests__/integration/mirador/plugins/priority.test.js
+++ b/__tests__/integration/mirador/plugins/priority.test.js
@@ -9,7 +9,7 @@ describe('try to apply 2 add plugins and 2 wrap plugins to <WorkspaceControlPane
   it('only apply the first wrap plugin', async () => {
     await expect(page).toMatchElement('#wrap-plugin-component-a');
     await expect(page).not.toMatchElement('#wrap-plugin-component-b');
-    await expect(page).not.toMatchElement('#add-plugin-component-a');
-    await expect(page).not.toMatchElement('#add-plugin-component-b');
+    await expect(page).toMatchElement('#add-plugin-component-a');
+    await expect(page).toMatchElement('#add-plugin-component-b');
   });
 });
diff --git a/__tests__/src/extend/withPlugins.test.js b/__tests__/src/extend/withPlugins.test.js
index 23e5bdbce..2e3ecf2cd 100644
--- a/__tests__/src/extend/withPlugins.test.js
+++ b/__tests__/src/extend/withPlugins.test.js
@@ -85,7 +85,7 @@ describe('PluginHoc: if add plugins exist but no wrap plugin', () => {
 });
 
 describe('PluginHoc: if wrap plugins AND add plugins exist for target', () => {
-  it('renders the first wrap plugin, ignores add plugins', () => {
+  it('renders the first wrap plugin, ignores add plugins if props are not passed through', () => {
     /** */ const WrapPluginComponentA = props => <div>look i am a plugin</div>;
     /** */ const WrapPluginComponentB = props => <div>look i am a plugin</div>;
     /** */ const AddPluginComponentA = props => <div>look i am a plugin</div>;
@@ -106,4 +106,27 @@ describe('PluginHoc: if wrap plugins AND add plugins exist for target', () => {
     expect(hoc.find(WrapPluginComponentA).length).toBe(1);
     expect(hoc.find(Target).length).toBe(0);
   });
+  it('renders the first wrap plugin, renders add plugins if plugin/props are passed through', () => {
+    /** */ const WrapPluginComponentA = plugin => (
+      <plugin.TargetComponent {...plugin.targetProps} {...plugin} />
+    );
+    /** */ const WrapPluginComponentB = props => <div>look i am a plugin</div>;
+    /** */ const AddPluginComponentA = props => <div>look i am a plugin</div>;
+    /** */ const AddPluginComponentB = props => <div>look i am a plugin</div>;
+    const plugins = {
+      Target: {
+        add: [
+          { component: AddPluginComponentA, mode: 'add', target: 'Target' },
+          { component: AddPluginComponentB, mode: 'add', target: 'Target' },
+        ],
+        wrap: [
+          { component: WrapPluginComponentA, mode: 'wrap', target: 'Target' },
+          { component: WrapPluginComponentB, mode: 'wrap', target: 'Target' },
+        ],
+      },
+    };
+    const hoc = createPluginHoc(plugins);
+    expect(hoc.find(WrapPluginComponentA).length).toBe(1);
+    expect(hoc.find(Target).length).toBe(1);
+  });
 });
diff --git a/src/components/WindowTopBarPluginMenu.js b/src/components/WindowTopBarPluginMenu.js
index f9b26d303..f57041539 100644
--- a/src/components/WindowTopBarPluginMenu.js
+++ b/src/components/WindowTopBarPluginMenu.js
@@ -45,7 +45,7 @@ export class WindowTopBarPluginMenu extends Component {
    */
   render() {
     const {
-      classes, containerId, PluginComponents, t, windowId,
+      classes, containerId, PluginComponents, t, windowId, menuIcon,
     } = this.props;
     const { anchorEl } = this.state;
 
@@ -60,7 +60,7 @@ export class WindowTopBarPluginMenu extends Component {
           className={anchorEl ? classes.ctrlBtnSelected : null}
           onClick={this.handleMenuClick}
         >
-          <MoreVertIcon />
+          {menuIcon}
         </MiradorMenuButton>
 
         <Menu
@@ -91,6 +91,7 @@ WindowTopBarPluginMenu.propTypes = {
     ctrlBtnSelected: PropTypes.string,
   }),
   containerId: PropTypes.string.isRequired,
+  menuIcon: PropTypes.element,
   PluginComponents: PropTypes.arrayOf(
     PropTypes.node,
   ),
@@ -101,5 +102,6 @@ WindowTopBarPluginMenu.propTypes = {
 
 WindowTopBarPluginMenu.defaultProps = {
   classes: {},
+  menuIcon: <MoreVertIcon />,
   PluginComponents: [],
 };
diff --git a/src/extend/withPlugins.js b/src/extend/withPlugins.js
index 59e929979..f7033bac4 100644
--- a/src/extend/withPlugins.js
+++ b/src/extend/withPlugins.js
@@ -26,6 +26,19 @@ function _withPlugins(targetName, TargetComponent) { // eslint-disable-line no-u
       return <TargetComponent {...passDownProps} />;
     }
 
+    if (!isEmpty(plugins.wrap) && !isEmpty(plugins.add)) {
+      const WrapPluginComponent = plugins.wrap[0].component;
+      const AddPluginComponents = plugins.add.map(plugin => plugin.component);
+      return (
+        <WrapPluginComponent
+          targetProps={passDownProps}
+          {...passDownProps}
+          PluginComponents={AddPluginComponents}
+          TargetComponent={TargetComponent}
+        />
+      );
+    }
+
     if (!isEmpty(plugins.wrap)) {
       const PluginComponent = plugins.wrap[0].component;
       return <PluginComponent targetProps={passDownProps} TargetComponent={TargetComponent} />;
-- 
GitLab