@harvard-lts/mirador-eda-plugin 0.1.7 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +26 -18
  2. package/dist/es/index.js +232 -218
  3. package/package.json +16 -11
package/README.md CHANGED
@@ -1,6 +1,24 @@
1
1
  # Mirador EDA Plugin
2
2
 
3
- A Mirador 3 plugin for displaying Emily Dickinson Archive (EDA) transcriptions with toggleable line breaks and editorial marks. This plugin replicates the viewing experience of [edickinson.org](https://www.edickinson.org) while gracefully handling non-Emily Dickinson manifests.
3
+ [![Node Unit Tests](https://github.com/harvard-lts/mirador-eda-plugin/actions/workflows/coverage-node.yml/badge.svg)](https://github.com/harvard-lts/mirador-eda-plugin/actions/workflows/coverage-node.yml)
4
+
5
+ <a href="https://github.com/harvard-lts/mirador-eda-plugin/actions/workflows/coverage-node.yml"><img src="https://github.com/harvard-lts/mirador-eda-plugin/raw/badges/test-coverage/coverage.svg"></a>
6
+
7
+ A Mirador plugin for displaying Emily Dickinson Archive (EDA) transcriptions with toggleable line breaks and editorial marks. This plugin replicates the viewing experience of [edickinson.org](https://www.edickinson.org) while gracefully handling non-Emily Dickinson manifests.
8
+
9
+ ## Compatibility
10
+
11
+ This plugin is **Mirador 4-compatible** (React 18/19, MUI 7 + Emotion). It is
12
+ **not** backwards compatible with Mirador 3 — the upgrade contains breaking
13
+ changes: top-level `mirador` imports (the deep `mirador/dist/es/src/...` paths no
14
+ longer resolve), function/hook components, and MUI 7 + Emotion styling in place
15
+ of Material-UI 4 + JSS.
16
+
17
+ Versioning convention for pinning:
18
+
19
+ - **Mirador 4** releases are tagged `2.x`.
20
+ - **Mirador 3** releases are tagged `0.x` / `1.x` — pin one of these if you still
21
+ need Mirador 3.
4
22
 
5
23
  ## Features
6
24
 
@@ -15,8 +33,8 @@ A Mirador 3 plugin for displaying Emily Dickinson Archive (EDA) transcriptions w
15
33
  ## Requirements
16
34
 
17
35
  - [NVM](https://github.com/nvm-sh/nvm)
18
- - Node.js 14+
19
- - Mirador 3.x
36
+ - Node.js 22+ (see `.nvmrc`)
37
+ - Mirador 4.x
20
38
 
21
39
  ## Setup
22
40
 
@@ -35,7 +53,7 @@ The following are some useful scripts can be ran using `npm run <script>`. A ful
35
53
 
36
54
  ## Installing in Mirador
37
55
 
38
- The `@harvard-lts/mirador-eda-plugin` requires an instance of Mirador 3. Visit the [Mirador wiki](https://github.com/ProjectMirador/mirador/wiki) to learn how to [install an existing plugin](https://github.com/ProjectMirador/mirador/wiki/Mirador-3-plugins#installing-an-existing-plugin) and for additional information about plugins.
56
+ The `@harvard-lts/mirador-eda-plugin` requires an instance of Mirador 4. Visit the [Mirador wiki](https://github.com/ProjectMirador/mirador/wiki) and the [Creating a Mirador 4 Plugin](https://github.com/ProjectMirador/mirador/wiki/Creating-a-Mirador-4-Plugin) page for information about installing and building plugins.
39
57
 
40
58
  ### Installation
41
59
 
@@ -118,19 +136,9 @@ npm test
118
136
 
119
137
  The development server will start at http://localhost:9000 and automatically reload when you make changes.
120
138
 
121
- ### Compatibility Notes
122
-
123
- The plugin includes a warning suppression utility for versions of Mirador prior to 4.0.0 that use a deprecated Material-UI Badge prop. This suppression:
124
-
125
- - Suppresses the `overlap="rectangle"` deprecation warning
126
- - Notes if the suppression file is no longer needed
127
- - Can be deleted once this app is upgraded to Mirador version 4.0.0 or later where the issue is fixed
128
-
129
- The warning suppression is implemented in `src/plugins/utils/suppressWarnings.js`.
130
-
131
139
  ### Testing
132
140
 
133
- The plugin includes comprehensive tests using Jest and React Testing Library. The test suite is organized by responsibility:
141
+ The plugin includes comprehensive tests using Vitest and React Testing Library. The test suite is organized by responsibility:
134
142
 
135
143
  ```bash
136
144
  # Run all tests
@@ -143,9 +151,9 @@ npm test src/plugins/__tests__/[filename].spec.js
143
151
  Test Files and Responsibilities:
144
152
 
145
153
  #### Component Tests
146
- - `EdaTranscriptionButton.spec.js` - Tests button rendering, visibility, and interaction
147
- - `EdaTranscriptionPanel.spec.js` - Tests panel UI, transcription display, and controls
148
- - `EdaSideBarButtonsWrapper.spec.js` - Tests sidebar button container and layout
154
+ - `EdaTranscriptionButton.spec.jsx` - Tests button rendering, visibility, and interaction
155
+ - `EdaTranscriptionPanel.spec.jsx` - Tests panel UI, transcription display, and controls
156
+ - `EdaSideBarButtonsWrapper.spec.jsx` - Tests sidebar button container and layout
149
157
 
150
158
  #### Manifest Tests
151
159
  - `edaManifest.spec.js` - Tests Emily Dickinson manifest handling and transcription extraction
package/dist/es/index.js CHANGED
@@ -1,12 +1,11 @@
1
- import { useState, createRef } from 'react';
2
- import CompanionWindow from 'mirador/dist/es/src/containers/CompanionWindow';
3
- import { compose } from 'redux';
1
+ import { useState, useRef } from 'react';
2
+ import { CompanionWindow } from 'mirador';
4
3
  import { connect, useSelector, shallowEqual } from 'react-redux';
5
- import { withStyles } from '@material-ui/core/styles';
6
- import { Typography, FormControl, Select, MenuItem, FormControlLabel, Checkbox } from '@material-ui/core';
7
- import { jsxs, jsx } from 'react/jsx-runtime';
8
- import TitleIcon from '@material-ui/icons/Title';
9
- import { version } from 'mirador/package.json';
4
+ import { styled } from '@mui/material/styles';
5
+ import GlobalStyles from '@mui/material/GlobalStyles';
6
+ import { Typography, FormControl, Select, MenuItem, FormControlLabel, Checkbox } from '@mui/material';
7
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
8
+ import TitleIcon from '@mui/icons-material/Title';
10
9
 
11
10
  function _arrayLikeToArray(r, a) {
12
11
  (null == a || a > r.length) && (a = r.length);
@@ -229,11 +228,100 @@ var getEdaTranscription = function getEdaTranscription(state, windowId) {
229
228
  return combinedTranscriptions;
230
229
  };
231
230
 
232
- var EdaTranscriptionPanel = function EdaTranscriptionPanel(_ref) {
233
- var classes = _ref.classes,
234
- transcriptions = _ref.transcriptions,
235
- windowId = _ref.windowId,
236
- id = _ref.id;
231
+ var PAPER_CLASS = "eda-transcription-paper";
232
+
233
+ // Global rules: the resize handle min-width and the companion window paper
234
+ // width. Previously expressed via JSS `@global` in withStyles.
235
+ var globalStyles = function globalStyles(theme) {
236
+ return _defineProperty({
237
+ ".react-draggable": _defineProperty(_defineProperty({}, theme.breakpoints.down("sm"), {
238
+ minWidth: "235px !important"
239
+ }), theme.breakpoints.up("sm"), {
240
+ minWidth: "350px !important" // this must match the paper minWidth
241
+ })
242
+ }, ".".concat(PAPER_CLASS), _defineProperty(_defineProperty({}, theme.breakpoints.down("sm"), {
243
+ minWidth: "235px"
244
+ }), theme.breakpoints.up("sm"), {
245
+ minWidth: "350px" // this must match the companion window minWidth
246
+ }));
247
+ };
248
+ var Root = styled("div")({
249
+ height: "100%",
250
+ overflow: "auto",
251
+ display: "flex",
252
+ flexDirection: "column"
253
+ });
254
+ var Controls = styled("div")(function (_ref2) {
255
+ var theme = _ref2.theme;
256
+ return {
257
+ padding: theme.spacing(2),
258
+ borderBottom: "1px solid ".concat(theme.palette.divider),
259
+ backgroundColor: theme.palette.background.paper
260
+ };
261
+ });
262
+
263
+ // The transcription content. Toggle classes (show-linebreaks / hide-edits)
264
+ // switch the display of injected markup. The nested selectors target the HTML
265
+ // set via dangerouslySetInnerHTML.
266
+ var Section = styled("div")(function (_ref3) {
267
+ var theme = _ref3.theme;
268
+ return {
269
+ flex: 1,
270
+ fontSize: ".875em",
271
+ lineHeight: theme.typography.body2.lineHeight,
272
+ fontFamily: theme.typography.fontFamily,
273
+ backgroundColor: theme.palette.background.paper,
274
+ borderRight: "0.5px solid ".concat(theme.palette.divider),
275
+ overflow: "auto",
276
+ color: theme.palette.text.primary,
277
+ padding: theme.spacing(2),
278
+ "& .line": {
279
+ display: "block"
280
+ },
281
+ "& ins:before": {
282
+ content: '"["',
283
+ fontWeight: theme.typography.fontWeightBold
284
+ },
285
+ "& ins:after": {
286
+ content: '"]"',
287
+ fontWeight: theme.typography.fontWeightBold
288
+ },
289
+ "& rt": {
290
+ fontSize: "0.833em"
291
+ },
292
+ "& .work-body": {
293
+ whiteSpace: "nowrap",
294
+ "& h3, & h4": {
295
+ fontWeight: theme.typography.fontWeightBold,
296
+ whiteSpace: "normal"
297
+ },
298
+ "& br": {
299
+ display: "none"
300
+ }
301
+ },
302
+ "&.show-linebreaks .work-body br": {
303
+ display: "block"
304
+ },
305
+ "&.hide-edits ins": {
306
+ display: "none"
307
+ },
308
+ "&.hide-edits rt": {
309
+ display: "none"
310
+ },
311
+ "& .stanza": {
312
+ marginBottom: theme.spacing(1.875)
313
+ },
314
+ "& .page-break": {
315
+ borderWidth: "1px 0 0 0",
316
+ borderStyle: "dotted",
317
+ display: "block !important"
318
+ }
319
+ };
320
+ });
321
+ var EdaTranscriptionPanel = function EdaTranscriptionPanel(_ref4) {
322
+ var transcriptions = _ref4.transcriptions,
323
+ windowId = _ref4.windowId,
324
+ id = _ref4.id;
237
325
  var _useState = useState(0),
238
326
  _useState2 = _slicedToArray(_useState, 2),
239
327
  selectedEdition = _useState2[0],
@@ -247,7 +335,7 @@ var EdaTranscriptionPanel = function EdaTranscriptionPanel(_ref) {
247
335
  hideEdits = _useState6[0],
248
336
  setHideEdits = _useState6[1];
249
337
  var currentTranscription = transcriptions[selectedEdition] || "";
250
- var contentRef = /*#__PURE__*/createRef();
338
+ var contentRef = useRef(null);
251
339
  var getEditionLabel = function getEditionLabel(html) {
252
340
  var _workBody$dataset;
253
341
  var parser = new DOMParser();
@@ -264,193 +352,117 @@ var EdaTranscriptionPanel = function EdaTranscriptionPanel(_ref) {
264
352
  var handleEditsChange = function handleEditsChange(event) {
265
353
  setHideEdits(event.target.checked);
266
354
  };
267
- var sectionClasses = [classes.section, showPhysicalLinebreaks ? "show-linebreaks" : "", hideEdits ? "hide-edits" : ""].filter(Boolean).join(" ");
355
+ var sectionClassName = ["section", showPhysicalLinebreaks ? "show-linebreaks" : "", hideEdits ? "hide-edits" : ""].filter(Boolean).join(" ");
268
356
 
269
357
  // CompanionWindow pulls the resizing functionality from Mirador
270
358
  // the paperClassName prop allows styles to the underlying container
271
- return /*#__PURE__*/jsxs(CompanionWindow, {
272
- title: "EDA Transcription",
273
- windowId: windowId,
274
- id: id,
275
- paperClassName: classes.paper,
276
- children: [(!transcriptions || transcriptions.length === 0) && /*#__PURE__*/jsx("div", {
277
- className: classes.root,
278
- children: /*#__PURE__*/jsx("div", {
279
- className: classes.section,
280
- children: /*#__PURE__*/jsx(Typography, {
281
- variant: "body1",
282
- className: classes.noTranscriptionsMessage,
283
- children: "Emily Dickinson Archive transcriptions are not available for this manuscript."
359
+ return /*#__PURE__*/jsxs(Fragment, {
360
+ children: [/*#__PURE__*/jsx(GlobalStyles, {
361
+ styles: globalStyles
362
+ }), /*#__PURE__*/jsxs(CompanionWindow, {
363
+ title: "EDA Transcription",
364
+ windowId: windowId,
365
+ id: id,
366
+ paperClassName: PAPER_CLASS
367
+ // Mirador exports the UNconnected CompanionWindow (`Nw`) as
368
+ // `CompanionWindow`; the connected variant (`ii`) that maps these from
369
+ // the companion-window's Redux record is internal and not exported. So
370
+ // we must supply them ourselves — without isDisplayed the paper renders
371
+ // with `display: none` and collapses to 0×0 (only the ins:before/after
372
+ // "[]" marks leak through), and without position it docks as "null"
373
+ // instead of in the left sidebar.
374
+ ,
375
+ isDisplayed: true,
376
+ position: "left"
377
+ // `direction` is normally injected by the connected wrapper from the
378
+ // viewer's text-direction state; the unconnected component reads
379
+ // O[direction].opposite and throws on undefined, so default it to ltr.
380
+ ,
381
+ direction: "ltr",
382
+ children: [(!transcriptions || transcriptions.length === 0) && /*#__PURE__*/jsx(Root, {
383
+ children: /*#__PURE__*/jsx("div", {
384
+ children: /*#__PURE__*/jsx(Typography, {
385
+ variant: "body1",
386
+ sx: {
387
+ padding: "16px"
388
+ },
389
+ children: "Emily Dickinson Archive transcriptions are not available for this manuscript."
390
+ })
284
391
  })
285
- })
286
- }), /*#__PURE__*/jsxs("div", {
287
- className: classes.root,
288
- children: [/*#__PURE__*/jsxs("div", {
289
- className: classes.controls,
290
- children: [transcriptions.length > 0 && /*#__PURE__*/jsxs(FormControl, {
291
- className: classes.formControl,
292
- children: [/*#__PURE__*/jsx(Typography, {
293
- variant: "body2",
294
- className: classes.editionLabel,
295
- children: "Edition"
296
- }), /*#__PURE__*/jsx(Select, {
297
- value: selectedEdition,
298
- onChange: handleEditionChange,
299
- variant: "outlined",
300
- margin: "dense",
301
- className: classes.selectInput,
302
- disabled: transcriptions.length === 1,
303
- children: transcriptions.map(function (transcription, index) {
304
- return /*#__PURE__*/jsx(MenuItem, {
305
- value: index,
306
- children: getEditionLabel(transcription)
307
- }, index);
308
- })
392
+ }), /*#__PURE__*/jsxs(Root, {
393
+ children: [/*#__PURE__*/jsxs(Controls, {
394
+ children: [transcriptions.length > 0 && /*#__PURE__*/jsxs(FormControl, {
395
+ sx: {
396
+ marginBottom: 1,
397
+ width: "100%"
398
+ },
399
+ children: [/*#__PURE__*/jsx(Typography, {
400
+ variant: "body2",
401
+ sx: {
402
+ fontWeight: "bold",
403
+ marginBottom: 0.5,
404
+ fontSize: "0.875rem"
405
+ },
406
+ children: "Edition"
407
+ }), /*#__PURE__*/jsx(Select, {
408
+ value: selectedEdition,
409
+ onChange: handleEditionChange,
410
+ variant: "outlined",
411
+ margin: "dense",
412
+ sx: {
413
+ width: {
414
+ xs: 230,
415
+ sm: 300
416
+ }
417
+ },
418
+ disabled: transcriptions.length === 1,
419
+ children: transcriptions.map(function (transcription, index) {
420
+ return /*#__PURE__*/jsx(MenuItem, {
421
+ value: index,
422
+ children: getEditionLabel(transcription)
423
+ }, index);
424
+ })
425
+ })]
426
+ }), /*#__PURE__*/jsx(FormControlLabel, {
427
+ control: /*#__PURE__*/jsx(Checkbox, {
428
+ checked: hideEdits,
429
+ onChange: handleEditsChange,
430
+ name: "edits",
431
+ color: "primary"
432
+ }),
433
+ label: "Hide Edits"
434
+ }), /*#__PURE__*/jsx(FormControlLabel, {
435
+ control: /*#__PURE__*/jsx(Checkbox, {
436
+ checked: showPhysicalLinebreaks,
437
+ onChange: handleLinebreaksChange,
438
+ name: "linebreaks",
439
+ color: "primary"
440
+ }),
441
+ label: "Physical Line Breaks"
309
442
  })]
310
- }), /*#__PURE__*/jsx(FormControlLabel, {
311
- control: /*#__PURE__*/jsx(Checkbox, {
312
- checked: hideEdits,
313
- onChange: handleEditsChange,
314
- name: "edits",
315
- color: "primary"
316
- }),
317
- label: "Hide Edits"
318
- }), /*#__PURE__*/jsx(FormControlLabel, {
319
- control: /*#__PURE__*/jsx(Checkbox, {
320
- checked: showPhysicalLinebreaks,
321
- onChange: handleLinebreaksChange,
322
- name: "linebreaks",
323
- color: "primary"
324
- }),
325
- label: "Physical Line Breaks"
443
+ }), /*#__PURE__*/jsx(Section, {
444
+ ref: contentRef,
445
+ className: sectionClassName,
446
+ dangerouslySetInnerHTML: {
447
+ __html: currentTranscription
448
+ }
326
449
  })]
327
- }), /*#__PURE__*/jsx("div", {
328
- ref: contentRef,
329
- className: sectionClasses,
330
- dangerouslySetInnerHTML: {
331
- __html: currentTranscription
332
- }
333
450
  })]
334
451
  })]
335
452
  });
336
453
  };
337
- var styles = function styles(theme) {
338
- return {
339
- "@global": {
340
- ".react-draggable": _defineProperty(_defineProperty({}, theme.breakpoints.down("sm"), {
341
- minWidth: "235px !important"
342
- }), theme.breakpoints.up("sm"), {
343
- minWidth: "350px !important" // this must match the paper minWidth
344
- })
345
- },
346
- root: {
347
- height: "100%",
348
- overflow: "auto",
349
- display: "flex",
350
- flexDirection: "column"
351
- },
352
- paper: _defineProperty(_defineProperty({}, theme.breakpoints.down("sm"), {
353
- minWidth: "235px"
354
- }), theme.breakpoints.up("sm"), {
355
- minWidth: "350px" // this must match the companion window minWidth
356
- }),
357
- controls: {
358
- padding: theme.spacing(2),
359
- borderBottom: "1px solid ".concat(theme.palette.divider),
360
- backgroundColor: theme.palette.background.paper
361
- },
362
- formControl: {
363
- marginBottom: theme.spacing(1),
364
- width: "100%"
365
- },
366
- editionLabel: {
367
- fontWeight: "bold",
368
- marginBottom: theme.spacing(0.5),
369
- fontSize: "0.875rem"
370
- },
371
- selectInput: _defineProperty(_defineProperty({}, theme.breakpoints.down("sm"), {
372
- width: 230
373
- }), theme.breakpoints.up("sm"), {
374
- width: 300
375
- }),
376
- section: {
377
- flex: 1,
378
- fontSize: ".875em",
379
- lineHeight: theme.typography.body2.lineHeight,
380
- fontFamily: theme.typography.fontFamily,
381
- backgroundColor: theme.palette.background.paper,
382
- borderRight: "0.5px solid ".concat(theme.palette.divider),
383
- overflow: "auto",
384
- color: theme.palette.text.primary,
385
- padding: theme.spacing(2),
386
- "& .line": {
387
- display: "block"
388
- },
389
- "& ins:before": {
390
- content: '"["',
391
- fontWeight: theme.typography.fontWeightBold
392
- },
393
- "& ins:after": {
394
- content: '"]"',
395
- fontWeight: theme.typography.fontWeightBold
396
- },
397
- "& rt": {
398
- fontSize: "0.833em"
399
- },
400
- "& .work-body": {
401
- whiteSpace: "nowrap",
402
- "& h3, & h4": {
403
- fontWeight: theme.typography.fontWeightBold,
404
- whiteSpace: "normal"
405
- },
406
- "& br": {
407
- display: "none"
408
- }
409
- },
410
- "&.show-linebreaks .work-body br": {
411
- display: "block"
412
- },
413
- "&.hide-edits ins": {
414
- display: "none"
415
- },
416
- "&.hide-edits rt": {
417
- display: "none"
418
- },
419
- "& .stanza": {
420
- marginBottom: theme.spacing(1.875)
421
- },
422
- "& .page-break": {
423
- borderWidth: "1px 0 0 0",
424
- borderStyle: "dotted",
425
- display: "block !important"
426
- }
427
- },
428
- noTranscriptionsMessage: {
429
- padding: "16px"
430
- }
431
- };
432
- };
433
- var mapStateToProps = function mapStateToProps(state, _ref2) {
434
- var windowId = _ref2.windowId;
454
+ var mapStateToProps = function mapStateToProps(state, _ref5) {
455
+ var windowId = _ref5.windowId;
435
456
  return {
436
457
  transcriptions: getEdaTranscription(state, windowId)
437
458
  };
438
459
  };
439
- var enhance = compose(withStyles(styles), connect(mapStateToProps));
440
460
  var EdaTranscriptionPanel$1 = {
441
- component: enhance(EdaTranscriptionPanel),
461
+ name: "EdaTranscriptionPanel",
462
+ component: connect(mapStateToProps)(EdaTranscriptionPanel),
442
463
  companionWindowKey: "edaTranscription"
443
464
  };
444
465
 
445
- var EdaTranscriptionButton = function EdaTranscriptionButton() {
446
- return /*#__PURE__*/jsx(TitleIcon, {
447
- "data-testid": "eda-transcription-icon"
448
- });
449
- };
450
-
451
- // this needs to match the companionWindowKey in EdaTranscriptionPanel.js
452
- EdaTranscriptionButton.value = "edaTranscription";
453
-
454
466
  var _excluded = ["TargetComponent"];
455
467
  var EdaSideBarButtonsWrapper = function EdaSideBarButtonsWrapper(_ref) {
456
468
  var TargetComponent = _ref.TargetComponent,
@@ -471,54 +483,56 @@ var EdaSideBarButtonsWrapper = function EdaSideBarButtonsWrapper(_ref) {
471
483
  };
472
484
  return originalTranslation(key, opts);
473
485
  };
474
-
475
- // if transcriptions exist, add EDA Transcriptions button
476
- var plugin = hasTranscriptions ? [EdaTranscriptionButton] : targetProps.PluginComponents;
477
486
  return /*#__PURE__*/jsx(TargetComponent, _objectSpread2(_objectSpread2({}, targetProps), {}, {
478
487
  t: customTranslation,
479
488
  panels: _objectSpread2(_objectSpread2({}, targetProps.panels), {}, {
480
489
  annotations: !hasTranscriptions
481
- }),
482
- PluginComponents: plugin
490
+ })
483
491
  }));
484
492
  };
485
493
  var EdaSideBarButtonsWrapper$1 = {
494
+ name: "EdaSideBarButtonsWrapper",
486
495
  target: "WindowSideBarButtons",
487
496
  mode: "wrap",
488
497
  component: EdaSideBarButtonsWrapper
489
498
  };
490
499
 
491
- // In Mirador version 3x there is a deprecation console warning:
492
- // Warning: Failed prop type: Material-UI: `overlap="rectangle"` was deprecated. Use `overlap="rectangular"` instead.
493
- // This was fixed in Mirador version 4.0.0
494
- // https://github.com/ProjectMirador/mirador/commit/90e695e0df5df44174a023cfae367a76e5697760
495
-
496
- // Suppressing this error to improve developer experience
497
-
498
- var FIXED_VERSION = "4.0.0";
499
- var parsedCurrentVersion = parseInt(version.replace(/\./g, ""));
500
- var parsedFixedVersion = parseInt(FIXED_VERSION.replace(/\./g, ""));
500
+ var EdaTranscriptionButton = function EdaTranscriptionButton(_ref) {
501
+ var windowId = _ref.windowId;
502
+ // shallowEqual prevents re-renders unless transcriptions actually change
503
+ var transcriptions = useSelector(function (state) {
504
+ return getEdaTranscription(state, windowId);
505
+ }, shallowEqual);
506
+ var hasTranscriptions = Boolean(transcriptions && transcriptions.length > 0);
507
+ if (!hasTranscriptions) return null;
508
+ return /*#__PURE__*/jsx(TitleIcon, {
509
+ "data-testid": "eda-transcription-icon"
510
+ });
511
+ };
501
512
 
502
- // Once the version is greater than or equal to the fixed version, we can remove this suppression
503
- if (parsedCurrentVersion >= parsedFixedVersion) {
504
- console.log("⚠️ Warning suppression for Material-UI Badge overlap prop may no longer be needed.\n" + " Current Mirador version: " + version + "\n" + " Fixed in version: " + FIXED_VERSION + "\n" + " Consider removing src/plugins/utils/suppressWarnings.js");
505
- } else {
506
- var originalConsoleError = console.error;
507
- console.error = function () {
508
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
509
- args[_key] = arguments[_key];
510
- }
511
- var suppressedWarnings = ["Material-UI: `overlap=\"rectangle\"` was deprecated. Use `overlap=\"rectangular\"` instead."];
512
- var shouldSuppress = suppressedWarnings.some(function (warning) {
513
- var _args$;
514
- return ((_args$ = args[0]) === null || _args$ === void 0 ? void 0 : _args$.includes) && args[0].includes(warning);
515
- });
516
- if (!shouldSuppress) {
517
- originalConsoleError.apply(console, args);
513
+ // this needs to match the companionWindowKey in EdaTranscriptionPanel.jsx;
514
+ // Mirador uses it as the tab value / companion window content key.
515
+ EdaTranscriptionButton.value = "edaTranscription";
516
+ var EdaTranscriptionButton$1 = {
517
+ name: "EdaTranscriptionButton",
518
+ target: "WindowSideBarButtons",
519
+ mode: "add",
520
+ component: EdaTranscriptionButton,
521
+ // Mirador 4's sidebar Tab renders its tooltip/aria-label from i18next via
522
+ // useTranslation() t("openCompanionWindow", { context: "edaTranscription" })
523
+ // not from any `t` prop. i18next resolves that to the key
524
+ // `openCompanionWindow_edaTranscription`. Mirador deep-merges each plugin's
525
+ // `config` into the global config, so shipping the translation here labels the
526
+ // tab "EDA Transcriptions" for every consumer without extra config.
527
+ config: {
528
+ translations: {
529
+ en: {
530
+ openCompanionWindow_edaTranscription: "EDA Transcriptions"
531
+ }
518
532
  }
519
- };
520
- }
533
+ }
534
+ };
521
535
 
522
- var index = [EdaSideBarButtonsWrapper$1, EdaTranscriptionPanel$1];
536
+ var index = [EdaSideBarButtonsWrapper$1, EdaTranscriptionButton$1, EdaTranscriptionPanel$1];
523
537
 
524
- export { EdaSideBarButtonsWrapper$1 as EdaSideBarButtonsWrapper, EdaTranscriptionPanel$1 as EdaTranscriptionPanel, index as default };
538
+ export { EdaSideBarButtonsWrapper$1 as EdaSideBarButtonsWrapper, EdaTranscriptionButton$1 as EdaTranscriptionButton, EdaTranscriptionPanel$1 as EdaTranscriptionPanel, index as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harvard-lts/mirador-eda-plugin",
3
- "version": "0.1.7",
3
+ "version": "2.0.0",
4
4
  "description": "A Mirador plugin for displaying Emily Dickinson Archive transcriptions with toggleable line breaks and editorial marks",
5
5
  "module": "dist/es/index.js",
6
6
  "files": [
@@ -15,6 +15,7 @@
15
15
  "build:es": "rollup -c",
16
16
  "serve": "vite",
17
17
  "test": "vitest run",
18
+ "test:unit": "node scripts/coverage-ci.mjs",
18
19
  "test:coverage": "vitest run --coverage",
19
20
  "test:watch": "vitest"
20
21
  },
@@ -35,18 +36,22 @@
35
36
  "license": "Apache-2.0",
36
37
  "homepage": "https://github.com/harvard-lts/mirador-eda-plugin#readme",
37
38
  "dependencies": {
39
+ "@emotion/react": "^11.11.0",
40
+ "@emotion/styled": "^11.11.0",
41
+ "@mui/icons-material": "^7.0.0",
42
+ "@mui/material": "^7.0.0",
43
+ "@mui/system": "^7.0.0",
38
44
  "jquery": "^3.7.0",
39
45
  "prop-types": "^15.8.1",
40
- "react": "^16.14.0",
41
- "react-dom": "^16.14.0",
42
- "redux": "^4.2.1",
46
+ "react": "^19.0.0",
47
+ "react-dom": "^19.0.0",
48
+ "react-i18next": "^15.0.0",
49
+ "redux": "^5.0.0",
43
50
  "redux-saga": "^1.2.3"
44
51
  },
45
52
  "peerDependencies": {
46
- "@material-ui/core": "^4.0.0",
47
- "@material-ui/icons": "^4.0.0",
48
- "mirador": "^3.0.0",
49
- "react-redux": "^5.0.0 || ^6.0.0 || ^7.0.0"
53
+ "mirador": "^4.0.0",
54
+ "react-redux": "^7.0.0 || ^8.0.0 || ^9.0.0"
50
55
  },
51
56
  "devDependencies": {
52
57
  "@babel/cli": "^7.26.4",
@@ -56,17 +61,17 @@
56
61
  "@reduxjs/toolkit": "^2.9.1",
57
62
  "@rollup/plugin-babel": "^6.0.3",
58
63
  "@testing-library/jest-dom": "^6.1.5",
59
- "@testing-library/react": "^12.0.0",
64
+ "@testing-library/react": "^16.0.0",
60
65
  "@vitejs/plugin-react": "^5.1.2",
61
66
  "@vitest/coverage-v8": "^4.0.17",
62
67
  "@vitest/ui": "^4.0.17",
63
68
  "jsdom": "^27.4.0",
64
- "mirador": "^3.4.3",
69
+ "mirador": "^4.1.0",
65
70
  "npm-run-all": "^4.1.5",
66
71
  "parcel": "^2.8.3",
67
72
  "rollup": "^3.29.5",
68
73
  "url": "^0.11.4",
69
- "vite": "^7.3.1",
74
+ "vite": "^8.0.16",
70
75
  "vitest": "^4.0.17"
71
76
  }
72
77
  }