Skip to content
Hillel Arnold edited this page Dec 21, 2020 · 5 revisions

Mirador 3 Plugins

What is a plugin?

Mirador plugins are a way for non-core code to inject components and other behavior into a Mirador application. The plugin configuration supplies information to Mirador about how to inject the plugin into the application:

const plugin = {
  target: 'WorkspaceControlPanelButtons',
  mode: 'wrap',
  component: PluginComponent,
  connectOptions: additionalOptionsToPassToReduxConnect,
  mapStateToProps: mapStateToProps,
  mapDispatchToProps: mapDispatchToProps,
  reducers: {
    pluginState: pluginStateReducer,
  },
  saga: saga,
  value: 'Button thing', # Only available in a WindowSideBarButtons add plugin
};

This form enables a plugin to do the following:

  1. Target an existing Mirador component
  2. Either wrap or add itself to that component. Note: add is only available on certain components
  3. Connect to the Mirador state using mapStateToProps, mapDispatchToProps, and connectOptions (see Redux#connect)
  4. provide custom reducers and a root saga for manipulating state.

The Mirador 3 plugin system is in active development. We invite the community to share their experiments and contributions in several areas:

  • Add your example the Example Plugins list below
  • Share your plugin at Mirador Community Call
  • Share your plugin on the Mirador tech group or the IIIF Slack #mirador-dev channel

See the mirador-plugin-demos repo for additional implementation examples.

Installing an existing plugin

An existing plugin (see the In Progress list below for some examples) can easily be added to a Mirador instance.

First, from the command line, install the javascript package:

$ npm install mirador-image-tools --save

and then add it to the plugins array before instantiating Mirador:

import miradorImageToolsPlugin from 'mirador-image-tools/es/plugins/miradorImageToolsPlugin.js';

const config = {
 ...
};

const plugins = [
  ...miradorImageToolsPlugin
];

Mirador.viewer(config, plugins);

Use mode=Add to inject additional content

Plugins with mode=add can be used to inject content into specifically designated areas within Mirador. We can discover where these areas are by looking for the PluginHook component, e.g.:

WindowTopBarPluginArea BackgroundPluginArea WorkspaceControlPanelButtons ManifestInfo

Let’s write a plugin to demonstrate this behavior. First, we need to build the component we want to render. Make a new directory at src/components, and create a new file in that directory called custom_metadata.js

import React, { Component } from 'react';

export default function () {
  return <h5>Custom metadata!</h5>;
}

In index.js, we can wire up our react component as a plugin:

import CustomMetadata from './components/custom_metadata';

const plugins = [
  {
    mode: 'add',
    component: CustomMetadata,
    target: 'CanvasInfo',
  }
];

If we take a look at the info sidebar panel, we’ll see our placeholder text. We could make our component blend in with Mirador a little better by adopting some of practices and markup from upstream:

import React, { Component } from 'react';
import Typography from '@material-ui/core/Typography';
import { LabelValueMetadata } from 'mirador/dist/es/src/components/LabelValueMetadata';

export default function () {
  return <>
    <Typography
      variant="h5"
      component="h6"
    >
      Custom metadata
    </Typography>
    <LabelValueMetadata labelValuePairs={[{ label: 'Cat?', values: ['Yes!'] }]} />
  </>;
}

Using mode=Wrap to override Mirador behavior

"Wrap" plugins can be used in several ways:

  • to entirely replace the content of a Mirador component
  • to literally wrap a Mirador component with some additional context
  • to intercept and modify the attributes of a component

Nearly all Mirador components can be wrapped, so this is a very powerful feature to inject your customizations in a very targeted way. Setting up a wrapping plugin is very similar to the add-style of plugin:

import CustomBrand from './components/custom_brand';

const plugins = [
  {
    mode: 'wrap',
    component: CustomBrand,
    target: 'Branding',
  }
];

and we can use a minimal component that just erases the whole brand:

import React, { Component } from 'react';

export default function ({}) {
  return <></>;
}

One of the unique things about wrapping components is they also receive the Mirador component they are wrapping, which makes it easy to surround the original component with additional context, or change the props that are used to render the component.

import React, { Component } from 'react';

export default function ({ TargetComponent, targetProps  }) {
  return <TargetComponent {...targetProps} />;
}

Integration

Here is an example of integrating Mirador plugins into an existing site: https://github.com/sul-dlss/sul-embed/blob/master/app/assets/javascripts/modules/m3_viewer.js#L97-L103

Example Plugins