Background

mirador-annotations is a plugin that adds annotation functionality to the IIIF viewer Mirador.

The previous project had the following configuration:

  • Build tool: nwb (Create React App based)
  • UI library: Material-UI v4
  • Mirador: 3.x
  • React: 17.x

However, the following problems were occurring:

  1. nwb maintenance stopped - nwb has not been updated for a long time, causing frequent dependency conflicts
  2. npm install failures - Old dependencies made setup in new environments difficult
  3. Security vulnerabilities - Numerous vulnerability warnings in old packages

To resolve these issues, we decided to migrate to:

  • Build tool: Vite
  • UI library: MUI v7
  • Mirador: 4.x
  • React: 18.x

Migration Work Overview

1. Build Tool Migration (nwb -> Vite)

Deleted the nwb configuration file and created a new vite.config.js.

Key points:

e}x)pcr};vooe;irntd}r}ttsue,e,etrfgsd].dnBilRoe,ceeenoeld''''ofn{cebsvu@@rrnava:aoepeeeefuull:emmaail=s{:v:ooccgtei{tttt.l'n[ii'-jdodggoo,dsearlnnofdaod//miEfburs'nntapet,ev-llayC(jTiclomshctenoia'dfdrst,'iee'e,g,f,(ep(pra{reconkmccaoeegdsseess.g}cl)wodb=(a>)l,{);

2. Material-UI Migration (v4 -> v7)

  • Changed @material-ui/* to @mui/*
  • Replaced makeStyles with sx prop
  • Addressed Grid component API changes (item and xs props unified into size)
<<GGrrBiAiedfdftoiesrtrieezm(e(M=MxU{UsI1I=2{v}v17>42))}>

3. Addressing Mirador 4.x Changes

In Mirador 4.x, the way actions and selectors are imported has changed:

iasirgmcemeeptlpctBoieAoeVerocfriiftntttvsosoeeir{.rr{Abersnlae.(rne(ccgMeoCMteeictaiiitreanrovVaitvaneidviadsAsoeoso,nirAnernbn(ssol4n.(3ete.o...laCxt..xeta)a).)cint)tovionaor(sns.e,.s}.(g).ef.tr.Vo)imsi'bmlierCaadnovra's;es}from'mirador';

Troublesome Points

1. menuItemRef.current.focus is not a function Error

Symptom

When navigating to a canvas that has annotations, the following error occurred:

TypeError:menuItemRef.current.focusisnotafunction

Cause

Mirador 4.x’s CanvasAnnotations component uses <MenuList autoFocusItem>. This autoFocusItem is a feature that automatically focuses on the first item in the list, but the element to be focused needs to have a focus() method.

The problem was in the CanvasListItem component:

c}lar}Psersnr)ode;bCet<larud/en(ri{dmv)nvtiaa>hvts{(i>iL{sci/.s*pctroIdodtipeevsm.rceehxciteleidnvrdeessn}Croemfp,onbeunttd{oesn'thavefocus()method/}

MUI’s MenuItem internally uses ref for focus control, but since CanvasListItem was a class component wrapping a <div>, the ref was not properly forwarded, causing the focus() method not found error.

Solution

Rewrote CanvasListItem as a function component and used forwardRef to directly forward the ref to the <li> element:

ic}}mo,)pnacr);osnre;rtnent<tofsul/Ct)triroo{{{lRaanenn./cient=[fMM.*h>avi>i(=oo.icaos{uuoltsn{Hrsstd,LioeeehridvfELee{s,e}nerntrtaP/}uIcievr}sthnreoeeig==pSml,{{stdFhh}a=rsoaateernnefntwdd,o,IallrsreeuwHdMMsaoooervruuCdoeessoRtrfeenehiELtfendnee(rgitax(P]revt{rere,o=c}}ptfsulosyrewStatoradtlReie(ffeal}lesmfeer)no;tm'react';

Lessons Learned

  • MUI v5+’s MenuList’s autoFocusItem expects child components to properly forward refs
  • When creating custom list item components, you need to use forwardRef to pass refs to DOM elements
  • When migrating from class components to function components, careful attention to ref handling is needed

2. CompanionWindow Not Displaying

Symptom

Clicking the “Create new annotation” button displayed nothing. Checking the console:

  • The addCompanionWindow action was dispatched correctly
  • The AnnotationCreation component’s render() was being called
  • But nothing was displayed on screen

Also, the following warning was appearing:

Wianrn`iCnogm:paFnaiiolneWdinpdroowp`,tybpuet:iTthsevparloupe`idsir`eucntdieofni`neids`.markedasrequired

Cause

Mirador exports two types of CompanionWindow components:

  1. CompanionWindow - Base component (requires manually passing props)
  2. ConnectedCompanionWindow - Redux-connected version (props are automatically retrieved from the store)

The pre-migration code was directly using CompanionWindow, but in Mirador 4.x, ConnectedCompanionWindow needed to be used.

impPoCtrroootmbpbl{aeenmCipaooatmnsipWscaienndcidooomdnwaeWniruneadqloulwiyr,}esbfurdtoimrteh'comtsiieroanad,roerp'oi;snittihoen,Readnudxostthoerreprops

Solution

Changed to import ConnectedCompanionWindow:

impFoirxted{ConnectedCompanionWindowasCompanionWindow}from'mirador';

This allowed the necessary props such as direction and position to be automatically retrieved from the Redux store.

Lessons Learned

  • Mirador components may have both a base version and a Redux-connected version
  • When developing plugins, it is necessary to verify which version to use
  • When “a component is rendered but not displayed,” suspect that required props may be missing

Other Items Addressed

draft-js global Reference Error

draft-js references the global object, but it doesn’t exist in browser environments. Addressed in the Vite configuration:

d}efgilnoeb:al{:'globalThis',

@emotion/react Duplication Warning

Caused by both Mirador and this plugin bundling @emotion/react. Resolved with resolve.dedupe:

<<GGrrBiAiedfdftoiesrtrieezm(e(M=MxU{UsI1I=2{v}v17>42))}>

0

Necessity of legacy-peer-deps

Since @psychobolt/react-paperjs requires React 17 as a peer dependency, legacy-peer-deps=true is still needed in .npmrc.


Summary

The two points that took the most time in this migration were:

  1. ref forwarding issues - It was necessary to understand MUI’s internal behavior and handle refs appropriately
  2. Using Connected components - It was necessary to understand Mirador’s export structure

Both were resolved by understanding the libraries’ internal implementations. During migration work, it is important to check the library source code, not just error messages.

Demo

The post-migration behavior can be tried at the following demo site:

https://nakamura196.github.io/mirador-annotations/