mirador-annotation-editor-video 1.1.5 → 1.1.7

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 (92) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/__tests__/AnnotationCreation.test.js +62 -28
  3. package/__tests__/AnnotationExportDialog.test.js +18 -16
  4. package/__tests__/CanvasListItem.test.js +53 -19
  5. package/__tests__/LocalStorageAdapter.test.js +1 -1
  6. package/__tests__/miradorAnnotationPlugin.test.js +97 -70
  7. package/__tests__/style-mock.js +1 -0
  8. package/__tests__/test-utils.js +57 -0
  9. package/demo/src/index.js +9 -4
  10. package/demo/src/quillConfig.js +34 -0
  11. package/es/AnnotationExportDialog.js +17 -25
  12. package/es/CanvasListItem.js +8 -4
  13. package/es/IIIFUtils.js +35 -3
  14. package/es/SingleCanvasDialog.js +1 -4
  15. package/es/TextEditor.js +9 -19
  16. package/es/annotationForm/AnnotationForm.js +14 -41
  17. package/es/annotationForm/AnnotationFormBody.js +36 -27
  18. package/es/annotationForm/AnnotationFormHeader.js +3 -3
  19. package/es/annotationForm/AnnotationFormOverlay/AnnotationDrawing.js +3 -1
  20. package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlay.js +1 -1
  21. package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +3 -2
  22. package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +8 -6
  23. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils.js +17 -19
  24. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ColorPicker.js +16 -6
  25. package/es/annotationForm/AnnotationFormTemplateSelector.js +9 -9
  26. package/es/annotationForm/AnnotationFormUtils.js +3 -0
  27. package/es/annotationForm/Debug.js +1 -0
  28. package/es/annotationForm/DebugInformation.js +27 -0
  29. package/es/annotationForm/MultiTagsInput.js +4 -1
  30. package/es/annotationForm/MultipleBodyTemplate.js +7 -9
  31. package/es/annotationForm/TaggingTemplate.js +0 -1
  32. package/es/annotationForm/TargetFormSection.js +4 -3
  33. package/es/annotationForm/TargetSpatialInput.js +4 -3
  34. package/es/annotationForm/TextCommentInput.js +25 -12
  35. package/es/annotationForm/TextCommentTemplate.js +0 -1
  36. package/es/annotationForm/UnsupportedMedia.js +43 -0
  37. package/es/containers/miradorAnnotationPlugin.js +1 -50
  38. package/es/custom.css +0 -13
  39. package/es/index.js +5 -12
  40. package/es/locales/locales.js +3 -2
  41. package/es/locales/locales_en.js +1 -1
  42. package/es/playerReferences.js +2 -1
  43. package/es/plugins/annotationCreationCompanionWindow.js +5 -8
  44. package/es/plugins/annotationSaga.js +44 -0
  45. package/es/plugins/canvasAnnotationsPlugin.js +86 -61
  46. package/es/plugins/canvasAnnotationsPluginUtils.js +202 -0
  47. package/es/plugins/externalStorageAnnotationPlugin.js +6 -71
  48. package/es/plugins/miradorAnnotationPlugin.js +44 -6
  49. package/es/plugins/windowSideBarButtonsPlugin.js +8 -10
  50. package/jest.config.js +14 -3
  51. package/package.json +8 -3
  52. package/setupJest.js +1 -4
  53. package/src/AnnotationExportDialog.js +12 -24
  54. package/src/CanvasListItem.js +4 -3
  55. package/src/IIIFUtils.js +33 -5
  56. package/src/SingleCanvasDialog.js +0 -3
  57. package/src/TextEditor.js +8 -32
  58. package/src/annotationForm/AnnotationForm.js +8 -47
  59. package/src/annotationForm/AnnotationFormBody.js +62 -83
  60. package/src/annotationForm/AnnotationFormHeader.js +3 -3
  61. package/src/annotationForm/AnnotationFormOverlay/AnnotationDrawing.js +3 -9
  62. package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlay.js +1 -1
  63. package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +2 -1
  64. package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +10 -6
  65. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils.js +25 -20
  66. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ColorPicker.js +14 -12
  67. package/src/annotationForm/AnnotationFormTemplateSelector.js +5 -7
  68. package/src/annotationForm/AnnotationFormUtils.js +2 -0
  69. package/src/annotationForm/Debug.js +0 -0
  70. package/src/annotationForm/DebugInformation.js +59 -0
  71. package/src/annotationForm/MultiTagsInput.js +4 -1
  72. package/src/annotationForm/MultipleBodyTemplate.js +7 -8
  73. package/src/annotationForm/TaggingTemplate.js +0 -1
  74. package/src/annotationForm/TargetFormSection.js +2 -3
  75. package/src/annotationForm/TargetSpatialInput.js +3 -3
  76. package/src/annotationForm/TextCommentInput.js +28 -14
  77. package/src/annotationForm/TextCommentTemplate.js +0 -1
  78. package/src/annotationForm/UnsupportedMedia.js +31 -0
  79. package/src/containers/miradorAnnotationPlugin.js +0 -36
  80. package/src/custom.css +0 -13
  81. package/src/index.js +10 -15
  82. package/src/locales/locales.js +3 -1
  83. package/src/locales/locales_en.js +1 -1
  84. package/src/playerReferences.js +5 -2
  85. package/src/plugins/annotationCreationCompanionWindow.js +9 -23
  86. package/src/plugins/annotationSaga.js +50 -0
  87. package/src/plugins/canvasAnnotationsPlugin.js +122 -98
  88. package/src/plugins/canvasAnnotationsPluginUtils.js +199 -0
  89. package/src/plugins/externalStorageAnnotationPlugin.js +6 -79
  90. package/src/plugins/miradorAnnotationPlugin.js +32 -4
  91. package/src/plugins/windowSideBarButtonsPlugin.js +6 -8
  92. package/webpack.config.js +1 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # CHANGELOG
2
+
3
+ ## [ 1.1.7]
4
+
5
+ - FIX : GetKonvaShape
6
+
7
+ ## [ 1.1.6]
8
+
9
+ ### Change From MAE 1.0.88
10
+ - ADD : Implement Multibody template
11
+ - ADD : Tags suggestion in annotation edition
12
+ - FIX : Use selector to get config data
13
+ - FIX : Clean translation function call
14
+ - FIX : Simplify IIIF annotation generation
15
+ - CLEAN : Remove unused code
@@ -1,48 +1,82 @@
1
1
  import React from 'react';
2
- import { shallow } from 'enzyme';
3
- import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
4
- import AnnotationCreation from '../src/AnnotationCreation';
5
- import AnnotationDrawing from '../src/AnnotationDrawing';
6
- import TextEditor from '../src/TextEditor';
7
- import ImageFormField from '../src/ImageFormField';
2
+
3
+ import {
4
+ fireEvent, render, screen, waitFor,
5
+ } from './test-utils';
6
+ import TextCommentTemplate from '../src/annotationForm/TextCommentTemplate';
7
+
8
+ const container = document.createElement('div');
9
+ container.setAttribute('data-testid', 'drawContainer');
10
+
11
+ const playerReferences = {
12
+ getContainer: jest.fn().mockReturnValue(container),
13
+ getDisplayedMediaHeight: jest.fn().mockReturnValue(100),
14
+ getDisplayedMediaWidth: jest.fn().mockReturnValue(200),
15
+ getImagePosition: jest.fn().mockReturnValue({ x: 0, y: 10 }),
16
+ getMediaTrueWidth: jest.fn().mockReturnValue(250),
17
+ getMediaType: jest.fn(),
18
+ getScale: jest.fn(),
19
+ getZoom: jest.fn(),
20
+ };
8
21
 
9
22
  /** */
10
23
  function createWrapper(props) {
11
- return shallow(
12
- <AnnotationCreation
13
- id="x"
14
- config={{ annotation: {} }}
15
- receiveAnnotation={jest.fn()}
24
+ const mockT = jest.fn().mockImplementation((key) => key);
25
+ return render(
26
+ <TextCommentTemplate
27
+ annotation={{}}
28
+ closeFormCompanionWindow={jest.fn()}
29
+ playerReferences={playerReferences}
30
+ saveAnnotation={jest.fn()}
31
+ t={mockT}
16
32
  windowId="abc"
17
33
  {...props}
18
34
  />,
19
35
  );
20
36
  }
21
37
 
22
- describe('AnnotationCreation', () => {
23
- let wrapper;
24
- it('renders a form', () => {
25
- wrapper = createWrapper();
26
- expect(wrapper.dive().find('form').length).toBe(1);
38
+ describe('TextCreation', () => {
39
+ it('renders a note', () => {
40
+ createWrapper();
41
+ expect(screen.getAllByText('note'));
27
42
  });
28
- it('form has button toggles', () => {
29
- wrapper = createWrapper();
30
- expect(wrapper.dive().find(ToggleButtonGroup).length).toBe(3);
43
+ it('has button tool selection', () => {
44
+ createWrapper();
45
+ screen.debug();
46
+
47
+ const toolSelection = screen.getByTestId('tool_selection');
48
+ expect(toolSelection).toBeInTheDocument();
49
+ const btns = screen.getAllByLabelText('select_cursor');
50
+ expect(btns).toHaveLength(3);
31
51
  });
32
52
  it('adds the AnnotationDrawing component', () => {
33
- wrapper = createWrapper();
34
- expect(wrapper.dive().find(AnnotationDrawing).length).toBe(1);
53
+ document.body.appendChild(container);
54
+ expect(screen.getByTestId('drawContainer')).toBeInTheDocument();
55
+
56
+ expect(container.querySelector('canvas')).not.toBeInTheDocument();
57
+ createWrapper();
58
+ expect(container.querySelector('canvas')).toBeInTheDocument();
59
+ document.body.removeChild(container);
35
60
  });
36
61
  it('adds the TextEditor component', () => {
37
- wrapper = createWrapper();
38
- expect(wrapper.dive().find(TextEditor).length).toBe(1);
62
+ createWrapper();
63
+ const textEditor = screen.getByTestId('textEditor');
64
+ expect(textEditor).toBeInTheDocument();
65
+ });
66
+ it('adds the annotation form footer', () => {
67
+ createWrapper();
68
+ expect(screen.getByRole('button', { name: 'save' })).toBeInTheDocument();
69
+ expect(screen.getByRole('button', { name: 'cancel' })).toBeInTheDocument();
39
70
  });
40
- it('adds the ImageFormField component', () => {
41
- wrapper = createWrapper();
42
- expect(wrapper.dive().find(ImageFormField).length).toBe(1);
71
+ it('adds the ImageFormField component', async () => {
72
+ createWrapper();
73
+ const toolSelection = screen.getByTestId('tool_selection');
74
+ expect(toolSelection).toBeInTheDocument();
75
+ expect(screen.getByLabelText('add_a_rectangle'));
76
+ expect(screen.getByLabelText('add_a_circle'));
43
77
  });
44
78
  it('can handle annotations without target selector', () => {
45
- wrapper = createWrapper({
79
+ const wrapper = createWrapper({
46
80
  annotation: {
47
81
  body: {
48
82
  purpose: 'commenting',
@@ -51,6 +85,6 @@ describe('AnnotationCreation', () => {
51
85
  target: {},
52
86
  },
53
87
  });
54
- wrapper.dive();
88
+ expect(wrapper).toBeDefined();
55
89
  });
56
90
  });
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
- import { shallow } from 'enzyme';
3
- import MenuItem from '@material-ui/core/MenuItem';
2
+
4
3
  import AnnotationExportDialog from '../src/AnnotationExportDialog';
4
+ import { screen, render, waitFor } from './test-utils';
5
5
 
6
6
  window.URL.createObjectURL = jest.fn((data) => ('downloadurl'));
7
7
 
@@ -22,12 +22,15 @@ const adapter = jest.fn(() => (
22
22
 
23
23
  /** */
24
24
  function createWrapper(props) {
25
- return shallow(
25
+ const mockT = jest.fn().mockImplementation((key) => key);
26
+ return render(
26
27
  <AnnotationExportDialog
27
28
  canvases={[]}
29
+ classes={{ listitem: 'testClass' }}
28
30
  config={{ annotation: { adapter } }}
29
31
  handleClose={jest.fn()}
30
32
  open
33
+ t={mockT}
31
34
  {...props}
32
35
  />,
33
36
  );
@@ -35,19 +38,18 @@ function createWrapper(props) {
35
38
 
36
39
  describe('AnnotationExportDialog', () => {
37
40
  it('renders download link for every annotation page', async () => {
38
- let wrapper = createWrapper({
39
- canvases: [
40
- { id: 'canvas/1' },
41
- { id: 'canvas/2' },
42
- ],
43
- }).dive();
44
- expect(wrapper.text()).toEqual(expect.stringContaining('No annotations stored yet.'));
41
+ createWrapper(
42
+ {
43
+ canvases: [
44
+ { id: 'canvas/1' },
45
+ { id: 'canvas/2' },
46
+ ],
47
+ },
48
+ );
49
+ expect(screen.getByText(/no_annotation/i)).toBeInTheDocument();
45
50
 
46
- wrapper.instance().componentDidUpdate({ open: false });
47
- await new Promise((resolve) => setTimeout(resolve, 50));
48
- wrapper = wrapper.update();
49
- expect(wrapper.text()).toEqual(expect.not.stringContaining('No annotations stored yet.'));
50
- expect(wrapper.find(MenuItem).some({ 'aria-label': 'Export annotations for canvas/1' })).toBe(true);
51
- expect(wrapper.find(MenuItem).some({ 'aria-label': 'Export annotations for canvas/2' })).toBe(true);
51
+ await waitFor(() => screen.getAllByText(/export_annotation_for/i));
52
+ const elements = screen.getAllByText(/export_annotation_for/);
53
+ expect(elements).toHaveLength(2);
52
54
  });
53
55
  });
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import { mount } from 'enzyme';
2
+
3
3
  import CanvasListItem from '../src/CanvasListItem';
4
4
  import AnnotationActionsContext from '../src/AnnotationActionsContext';
5
+ import { render, screen, fireEvent } from './test-utils';
5
6
 
6
7
  const receiveAnnotation = jest.fn();
7
8
  const storageAdapter = jest.fn(() => (
@@ -20,7 +21,7 @@ const storageAdapter = jest.fn(() => (
20
21
 
21
22
  /** */
22
23
  function createWrapper(props, context = {}) {
23
- return mount(
24
+ return render(
24
25
  <AnnotationActionsContext.Provider
25
26
  value={{
26
27
  canvases: [],
@@ -44,13 +45,13 @@ function createWrapper(props, context = {}) {
44
45
  }
45
46
 
46
47
  describe('CanvasListItem', () => {
47
- let wrapper;
48
48
  it('wraps its children', () => {
49
- wrapper = createWrapper();
50
- expect(wrapper.find(CanvasListItem).find('li').text()).toBe('HelloWorld');
49
+ createWrapper();
50
+ expect(screen.getByText('HelloWorld')).toBeInTheDocument();
51
51
  });
52
+
52
53
  it('shows an edit and delete button when it matches an editable annotationid and is hovering', () => {
53
- wrapper = createWrapper({}, {
54
+ createWrapper({}, {
54
55
  annotationsOnCanvases: {
55
56
  'canv/1': {
56
57
  'annoPage/1': {
@@ -58,6 +59,7 @@ describe('CanvasListItem', () => {
58
59
  items: [
59
60
  {
60
61
  id: 'anno/1',
62
+ maeData: true,
61
63
  },
62
64
  ],
63
65
  },
@@ -70,23 +72,55 @@ describe('CanvasListItem', () => {
70
72
  },
71
73
  ],
72
74
  });
73
- wrapper.setState({ isHovering: true });
74
- expect(wrapper.find('ForwardRef(ToggleButton)').length).toBe(3);
75
+ const annotationElement = screen.getAllByRole('listitem').find(
76
+ (el) => el.getAttribute('annotationid') === 'anno/1',
77
+ );
78
+
79
+ fireEvent.mouseEnter(annotationElement);
80
+
81
+ const buttons = screen.getAllByRole('button');
82
+ expect(buttons.length).toBe(3);
83
+ expect(screen.getByRole('button', { name: /metadata/i })).toBeInTheDocument();
84
+ expect(screen.getByRole('button', { name: /edit/i })).toBeInTheDocument();
85
+ expect(screen.getByRole('button', { name: /delete/i })).toBeInTheDocument();
75
86
  });
87
+
76
88
  it('deletes from a storageAdapter when handling deletes', async () => {
77
- wrapper = createWrapper(
78
- {
79
- annotationid: 'anno/1',
80
- },
81
- {
82
- canvases: [
83
- {
84
- id: 'canvas/1',
89
+ createWrapper({}, {
90
+ annotationEditCompanionWindowIsOpened: true,
91
+ annotationsOnCanvases: {
92
+ 'canv/1': {
93
+ 'annoPage/1': {
94
+ json: {
95
+ items: [
96
+ {
97
+ id: 'anno/1',
98
+ maeData: true,
99
+ },
100
+ ],
101
+ },
85
102
  },
86
- ],
103
+ },
87
104
  },
105
+ canvases: [
106
+ {
107
+ id: 'canv/1',
108
+ },
109
+ ],
110
+ });
111
+
112
+ const annotationElement = screen.getAllByRole('listitem').find(
113
+ (el) => el.getAttribute('annotationid') === 'anno/1',
114
+ );
115
+ fireEvent.mouseEnter(annotationElement);
116
+
117
+ const deleteButton = screen.getByRole('button', { name: /delete/i });
118
+
119
+ fireEvent.click(deleteButton);
120
+
121
+ expect(storageAdapter).toHaveBeenCalledTimes(1);
122
+ expect(storageAdapter).toHaveBeenCalledWith(
123
+ 'canv/1',
88
124
  );
89
- await wrapper.instance().handleDelete();
90
- expect(receiveAnnotation).toHaveBeenCalledWith('canvas/1', 'pageId/3', 'annoPageResultFromDelete');
91
125
  });
92
126
  });
@@ -1,4 +1,4 @@
1
- import LocalStorageAdapter from '../src/LocalStorageAdapter';
1
+ import LocalStorageAdapter from '../src/annotationAdapter/LocalStorageAdapter';
2
2
  import fixture from '../__fixtures__/web_annotation.json';
3
3
 
4
4
  describe('LocalStorageAdapter', () => {
@@ -1,87 +1,114 @@
1
1
  import React from 'react';
2
- import { shallow } from 'enzyme';
3
- import { MiradorMenuButton } from 'mirador/dist/es/src/components/MiradorMenuButton';
4
- import LocalStorageAdapter from '../src/LocalStorageAdapter';
5
- import miradorAnnotationPlugin from '../src/plugins/miradorAnnotationPlugin';
2
+ import { useDispatch } from 'react-redux';
3
+
4
+ import { getWindowViewType } from 'mirador/dist/es/src/state/selectors';
5
+ import LocalStorageAdapter from '../src/annotationAdapter/LocalStorageAdapter';
6
+ import MiradorAnnotation from '../src/plugins/miradorAnnotationPlugin';
7
+ import { render, screen, fireEvent } from './test-utils';
8
+
9
+ jest.mock('react-redux', () => ({
10
+ ...jest.requireActual('react-redux'),
11
+ useDispatch: jest.fn(),
12
+ }));
13
+ jest.mock('mirador/dist/es/src/state/selectors', () => ({
14
+ getWindowViewType: jest.fn(),
15
+ }));
16
+
17
+ const defaultInitalState = {
18
+ config: {
19
+ annotation: {
20
+ adapter: jest.fn(),
21
+ exportLocalStorageAnnotations: true,
22
+ },
23
+ },
24
+ };
6
25
 
7
26
  /** */
8
- function createWrapper(props) {
9
- return shallow(
10
- <miradorAnnotationPlugin.component
11
- canvases={[]}
12
- config={{}}
13
- TargetComponent="<div>hello</div>"
14
- targetProps={{}}
15
- addCompanionWindow={jest.fn()}
16
- receiveAnnotation={jest.fn()}
17
- switchToSingleCanvasView={jest.fn()}
18
- windowViewType="single"
19
- {...props}
20
- />,
21
- );
27
+ function createWrapper(props, initalState = defaultInitalState) {
28
+ const mockT = jest.fn().mockImplementation((key) => key);
29
+
30
+ return render(<MiradorAnnotation
31
+ canvases={[]}
32
+ config={{}}
33
+ TargetComponent={() => <div>hello</div>}
34
+ targetProps={{ windowId: 'windowId' }}
35
+ receiveAnnotation={jest.fn()}
36
+ switchToSingleCanvasView={jest.fn()}
37
+ annotationEditCompanionWindowIsOpened
38
+ t={mockT}
39
+ {...props}
40
+ />, { preloadedState: initalState });
22
41
  }
23
42
 
24
43
  describe('MiradorAnnotation', () => {
25
- let wrapper;
26
44
  it('renders a create new button', () => {
27
- wrapper = createWrapper();
28
- expect(wrapper.find(MiradorMenuButton).props()['aria-label']).toBe('Create new annotation');
45
+ createWrapper();
46
+ const button = screen.getByRole('button', { name: /create_annotation/i });
47
+ expect(button).toBeInTheDocument();
29
48
  });
49
+
30
50
  it('opens a new companionWindow when clicked', () => {
31
- const mockAddCompanionWindow = jest.fn();
32
- const receiveAnnotationMock = jest.fn();
33
- wrapper = createWrapper({
34
- addCompanionWindow: mockAddCompanionWindow,
35
- receiveAnnotation: receiveAnnotationMock,
36
- });
37
- wrapper.find(MiradorMenuButton).simulate('click');
38
- expect(mockAddCompanionWindow).toHaveBeenCalledWith(
39
- 'annotationCreation',
40
- {
41
- position: 'right',
42
- },
51
+ const mockDispatch = jest.fn();
52
+ useDispatch.mockImplementation(() => mockDispatch);
53
+
54
+ getWindowViewType.mockReturnValue('single');
55
+ createWrapper({});
56
+
57
+ const button = screen.getByRole('button', { name: /create_annotation/i });
58
+ fireEvent.click(button);
59
+
60
+ expect(mockDispatch).toHaveBeenCalledTimes(1);
61
+ const dispatchedAction = mockDispatch.mock.calls[0][0];
62
+ expect(dispatchedAction).toEqual(
63
+ expect.objectContaining({
64
+ payload: expect.objectContaining({
65
+ content: 'annotationCreation',
66
+ position: 'right',
67
+ }),
68
+ type: 'mirador/ADD_COMPANION_WINDOW',
69
+ windowId: 'windowId',
70
+ }),
43
71
  );
44
72
  });
73
+
45
74
  it('opens single canvas view dialog if not in single view', () => {
46
- wrapper = createWrapper({
47
- windowViewType: 'book',
48
- });
49
- expect(wrapper.instance().state.singleCanvasDialogOpen).toBe(false);
50
- wrapper.find(MiradorMenuButton).simulate('click');
51
- expect(wrapper.instance().state.singleCanvasDialogOpen).toBe(true);
75
+ getWindowViewType.mockReturnValue('book');
76
+ createWrapper();
77
+
78
+ expect(screen.queryByText('switch_view')).toBeNull();
79
+ const button = screen.getByRole('button', { name: /create_annotation/i });
80
+ fireEvent.click(button);
81
+
82
+ expect(screen.queryByText('Switch to single view')).toBeInTheDocument();
52
83
  });
84
+
53
85
  it('renders no export button if export or LocalStorageAdapter are not configured', () => {
54
- wrapper = createWrapper();
55
- expect(wrapper.find(MiradorMenuButton).some({ 'aria-label': 'Export local annotations for visible items' })).toBe(false);
56
-
57
- wrapper = createWrapper({
58
- config: {
59
- annotation: {
60
- adapter: () => () => {},
61
- exportLocalStorageAnnotations: true,
62
- },
63
- },
64
- });
65
- expect(wrapper.find(MiradorMenuButton).some({ 'aria-label': 'Export local annotations for visible items' })).toBe(false);
66
-
67
- wrapper = createWrapper({
68
- config: {
69
- annotation: {
70
- adapter: (canvasId) => new LocalStorageAdapter(`test://?canvasId=${canvasId}`),
71
- },
72
- },
73
- });
74
- expect(wrapper.find(MiradorMenuButton).some({ 'aria-label': 'Export local annotations for visible items' })).toBe(false);
86
+ // eslint-disable-next-line max-len
87
+ const stateWithoutLocalAdapter = { config: { annotation: { adapter: () => () => {}, exportLocalStorageAnnotations: true } } };
88
+ createWrapper({}, stateWithoutLocalAdapter);
89
+ const button = screen.queryByText(/Export local annotations for visible items/i);
90
+ expect(button).toBeNull();
91
+
92
+ const annotation = {
93
+ adapter: () => () => {}, exportLocalStorageAnnotations: false,
94
+ };
95
+
96
+ const stateWithFalsyExport = { config: annotation };
97
+ createWrapper({}, stateWithFalsyExport);
98
+ const button2 = screen.queryByText(/Export local annotations for visible items/i);
99
+ expect(button2).toBeNull();
75
100
  });
76
- it('renders export button if export and LocalStorageAdapter are configured', () => {
77
- wrapper = createWrapper({
78
- config: {
79
- annotation: {
80
- adapter: (canvasId) => new LocalStorageAdapter(`test://?canvasId=${canvasId}`),
81
- exportLocalStorageAnnotations: true,
82
- },
83
- },
84
- });
85
- expect(wrapper.find(MiradorMenuButton).some({ 'aria-label': 'Export local annotations for visible items' })).toBe(true);
101
+
102
+ xit('renders export button if export and LocalStorageAdapter are configured', () => {
103
+ const annotation = {
104
+ adapter: () => new LocalStorageAdapter(),
105
+ exportLocalStorageAnnotations: true,
106
+ };
107
+
108
+ const initalState = { config: { annotation } };
109
+ createWrapper({}, initalState);
110
+
111
+ const button = screen.getByRole('button', { name: /Export local annotations for visible items/i });
112
+ expect(button).toBeInTheDocument();
86
113
  });
87
114
  });
@@ -0,0 +1 @@
1
+ module.exports = {};
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { Provider } from 'react-redux';
3
+
4
+ import createRootReducer from 'mirador/dist/es/src/state/reducers/rootReducer';
5
+ import settings from 'mirador/dist/es/src/config/settings';
6
+
7
+ import { createTheme, ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
8
+ import { render } from '@testing-library/react';
9
+ import { createStore, applyMiddleware } from 'redux';
10
+ import { thunk } from 'redux-thunk';
11
+ import PropTypes from 'prop-types';
12
+
13
+ const rootReducer = createRootReducer();
14
+ const theme = createTheme(settings.theme);
15
+
16
+ /**
17
+ * Hook up our rendered object to redux
18
+ */
19
+ function renderWithProviders(
20
+ ui,
21
+ {
22
+ preloadedState = {},
23
+ // Automatically create a store instance if no store was passed in
24
+ store = createStore(rootReducer, preloadedState, applyMiddleware(thunk)),
25
+ ...renderOptions
26
+ } = {},
27
+ ) {
28
+ /** :nodoc: */
29
+ function Wrapper({ children }) {
30
+ return (
31
+ <StyledEngineProvider injectFirst>
32
+ <ThemeProvider theme={theme}>
33
+ <Provider store={store}>{children}</Provider>
34
+ </ThemeProvider>
35
+ </StyledEngineProvider>
36
+ );
37
+ }
38
+
39
+ Wrapper.propTypes = {
40
+ children: PropTypes.node.isRequired,
41
+ };
42
+
43
+ const rendered = render(ui, { wrapper: Wrapper, ...renderOptions });
44
+
45
+ // Return an object with the store and all of RTL's query functions
46
+ return {
47
+ store,
48
+ ...rendered,
49
+ rerender: (newUi, options) => render(
50
+ newUi,
51
+ { container: rendered.container, wrapper: Wrapper, ...options },
52
+ ),
53
+ };
54
+ }
55
+
56
+ export * from '@testing-library/react';
57
+ export { renderWithProviders as render };
package/demo/src/index.js CHANGED
@@ -2,19 +2,22 @@ import mirador from 'mirador/dist/es/src/index';
2
2
  import annotationPlugins from '../../src';
3
3
  import LocalStorageAdapter from '../../src/annotationAdapter/LocalStorageAdapter';
4
4
  import { manifestsCatalog } from './manifestsCatalog';
5
+ import { quillConfig } from './quillConfig';
5
6
 
6
7
  const config = {
7
8
  annotation: {
8
9
  adapter: (canvasId) => new LocalStorageAdapter(`localStorage://?canvasId=${canvasId}`, 'Anonymous User'),
10
+ allowTargetShapesStyling: false,
9
11
  commentTemplates: [{
12
+ content: '<h4>Comment</h4><p>Comment content</p>',
10
13
  title: 'Template',
11
- content: '<h4>Comment</h4><p>comment content</p>',
12
14
  },
13
15
  {
16
+ content: '<h4>Comment2</h4><p>Comment content</p>',
14
17
  title: 'Template 2',
15
- content: '<h4>Comment2</h4><p>comment content</p>',
16
18
  }],
17
- exportLocalStorageAnnotations: false, // display annotation JSON export button
19
+ exportLocalStorageAnnotations: false,
20
+ quillConfig,
18
21
  tagsSuggestions: ['Mirador', 'Awesome', 'Viewer', 'IIIF', 'Template'],
19
22
  },
20
23
  annotations: {
@@ -66,7 +69,9 @@ const config = {
66
69
  defaultSideBarPanel: 'annotations',
67
70
  sideBarOpenByDefault: true,
68
71
  },
69
- windows: [],
72
+ windows: [
73
+ { manifestId: ' https://iiif.harvardartmuseums.org/manifests/object/299843' },
74
+ ],
70
75
  };
71
76
 
72
77
  mirador.viewer(config, [...annotationPlugins]);
@@ -0,0 +1,34 @@
1
+ export const quillConfig = {
2
+ // https://quilljs.com/docs/formats
3
+ formats: [
4
+ 'header',
5
+ 'bold',
6
+ 'italic',
7
+ 'underline',
8
+ 'strike',
9
+ 'blockquote',
10
+ 'list',
11
+ 'bullet',
12
+ 'indent',
13
+ 'link',
14
+ 'image',
15
+ 'color',
16
+ 'background',
17
+ ],
18
+ // https://quilljs.com/docs/modules/toolbar/
19
+ modules: {
20
+ toolbar: [
21
+ [{ header: [1, 2, false] }],
22
+ ['bold', 'italic', 'underline', 'strike', 'blockquote'],
23
+ [
24
+ { list: 'ordered' },
25
+ { list: 'bullet' },
26
+ { indent: '-1' },
27
+ { indent: '+1' },
28
+ ],
29
+ [{ color: [] }, { background: [] }],
30
+ ['link', 'image'],
31
+ ['clean'],
32
+ ],
33
+ },
34
+ };