mirador-annotation-editor-video 1.0.98 → 1.1.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.
package/README.md CHANGED
@@ -4,57 +4,54 @@
4
4
 
5
5
  ### Generalities
6
6
 
7
- `mirador-annotation-editor-video`(also known as "MAEV") is a [Mirador 4](https://github.com/projectmirador/mirador) plugin that
7
+ `mirador-annotation-editor-video`(also known as "MAEV") is a [Mirador 4](https://github.com/projectmirador/mirador)
8
+ plugin that
8
9
  adds annotation creation tools to the user interface. It support both image and video annotation.
9
10
 
10
11
  ### Copyrights
11
12
 
13
+ Originally forked from https://github.com/ARVEST-APP/mirador-annotation-editor-video
14
+
12
15
  #### Licence
13
16
 
14
17
  This plugin is released under the **GPL v3** license unlike MAE and the original plugin.
15
18
 
16
- Please acknowledge that any modification you make must be distributed under a compatible licence and cannot be closed
19
+ Please acknowledge that any modification you make must be distributed under a compatible licence and cannot be closed
17
20
  source.
18
21
 
19
- If you need to integrate this code base in closed source pieces of software, please contact us, so we can discuss dual
20
- licencing.
21
-
22
- #### Property
23
-
24
- The base of this software (up to V1) is the property of [SATT Ouest Valorisation](https://www.ouest-valorisation.fr/)
25
- that funded its development under the French public contract AO-MA2023-0004-DV5189.
22
+ If you need to integrate this code base in closed source pieces of software, please contact us, so we can discuss dual
23
+ licencing.
26
24
 
27
- #### Authors
25
+ #### Authors
28
26
 
29
27
  The authors of this software are :
30
28
 
31
29
  - Clarisse Bardiot (concept and use cases)
32
30
  - Jacob Hart (specifications)
33
31
  - [Tétras Libre SARL](https://tetras-libre.fr) (development):
34
- - David Rouquet
35
- - Anthony Geourjon
36
- - Antoine Roy
32
+ - David Rouquet
33
+ - Anthony Geourjon
34
+ - Antoine Roy
37
35
 
38
36
  #### Contributors (updated february 2024)
39
37
 
40
- - AZOPSOFT SAS
41
- - Samuel Jugnet (especially code for the Konvas part)
42
- - Loïs Poujade (especially the original modifications to annotate videos)
38
+ - AZOPSOFT SAS
39
+ - Samuel Jugnet (especially code for the Konvas part)
43
40
 
44
- ### General functionalities
41
+ ### General functionalities
45
42
 
46
- - Activate a panel with tools to create annotations on IIIF documents (manifests) containing images **and videos with
47
- MAEV**
43
+ - Activate a panel with tools to create annotations on IIIF documents (manifests) containing images **and videos with
44
+ MAEV**
48
45
  - Spatial and temporal targets for annotations
49
46
  - Overlay annotations (geometric forms, free hand drawing, text and images)
50
47
  - Textual/semantic annotations and tags
51
48
  - Annotation metadata (based on Dublin Core)
52
49
  - Annotation with another manifest -> network of IIIF documents
53
50
 
54
- ### Technical aspects
51
+ ### Technical aspects
55
52
 
56
53
  - Update to Material UI 5 and React 18 to follow latest Mirador upgrades (We support mirador": "4.0.0-alpha.2",
57
- - The [paperjs](http://paperjs.org/ ) library has been replaced with [Konvas](https://konvajs.org)
54
+ - The [paperjs](http://paperjs.org/ ) library has been replaced with [Konvas](https://konvajs.org)
58
55
  - Major refactoring since the original `[mirador-annotations](https://github.com/ProjectMirador/mirador-annotations/)
59
56
  plugins`
60
57
  - Works with the original [Mirador 4](https://github.com/projectmirador/mirador) if you need only image annotation
@@ -70,18 +67,22 @@ npm install mirador-annotation-editor
70
67
  You can override existing annotation plugin with your own versions by using npm. We support React 18 and MUI 5.
71
68
 
72
69
  Update your `package.json` file to include the following dependencies and devDependencies:
70
+
73
71
  ```js
74
- "mirador-annotations": "npm:mirador-annotation-editor-video@^1.0.10",
72
+ "mirador-annotations"
73
+ :
74
+ "npm:mirador-annotation-editor-video@^1.0.10",
75
75
  ```
76
76
 
77
77
  You need also to use the custom version of Mirador 4.
78
78
 
79
79
  ```js
80
- "mirador" : "npm@mirador-video@^1.0.17",
80
+ "mirador"
81
+ :
82
+ "npm@mirador-video@^1.0.17",
81
83
  ```
82
84
 
83
- If you encounter this error :
84
-
85
+ If you encounter this error :
85
86
 
86
87
  ## Install (local)
87
88
 
@@ -101,23 +102,23 @@ npm start
101
102
  ```
102
103
 
103
104
  ## Use MAE with video annotation support
104
- - If you need video annotation, you can use
105
- [our fork of Mirador: mirador-video](https://github.com/SCENE-CE/mirador-video)
106
- - In addition, we have developed a wrapper of MAE to support video annotation. This wrapper is called **MAEV** and is
107
- available in the [mirador-annotation-editor-video](https://github.com/SCENE-CE/mirador-annotation-editor-video)
108
- repository.
109
105
 
106
+ - If you need video annotation, you can use
107
+ [our fork of Mirador: mirador-video](https://github.com/SCENE-CE/mirador-video)
108
+ - In addition, we have developed a wrapper of MAE to support video annotation. This wrapper is called **MAEV** and is
109
+ available in the [mirador-annotation-editor-video](https://github.com/SCENE-CE/mirador-annotation-editor-video)
110
+ repository.
110
111
 
111
112
  ## Persisting Annotations
112
- Persisting annotations requires implementing a IIIF annotation server. Several
113
+
114
+ Persisting annotations requires implementing a IIIF annotation server. Several
113
115
  [examples of annotation servers](https://github.com/IIIF/awesome-iiif#annotation-servers) are available on iiif-awesome.
114
116
 
115
- `mirador-annotation-editor` currently supports adapters for
116
- [annotot](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/AnnototAdapter.js) and
117
- [local storage](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/LocalStorageAdapter.js). We
117
+ `mirador-annotation-editor` currently supports adapters for
118
+ [annotot](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/AnnototAdapter.js) and
119
+ [local storage](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/LocalStorageAdapter.js). We
118
120
  welcome contributions of adapters for other annotation servers.
119
121
 
120
-
121
122
  ## Contribute
122
123
 
123
124
  Our plugin follow the Mirador guidelines. Development, design, and maintenance is driven by community needs and ongoing
package/demo/src/index.js CHANGED
@@ -6,7 +6,14 @@ import { manifestsCatalog } from './manifestsCatalog';
6
6
  const config = {
7
7
  annotation: {
8
8
  adapter: (canvasId) => new LocalStorageAdapter(`localStorage://?canvasId=${canvasId}`, 'Anonymous User'),
9
- commentTemplate: '<h4>Comment</h4><p>comment content</p>',
9
+ commentTemplates: [{
10
+ title: 'Template',
11
+ content: '<h4>Comment</h4><p>comment content</p>',
12
+ },
13
+ {
14
+ title: 'Template 2',
15
+ content: '<h4>Comment2</h4><p>comment content</p>',
16
+ }],
10
17
  exportLocalStorageAnnotations: false, // display annotation JSON export button
11
18
  tagsSuggestions: ['Mirador', 'Awesome', 'Viewer', 'IIIF'],
12
19
  },
package/es/TextEditor.js CHANGED
@@ -4,14 +4,12 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireWildcard(require("react"));
7
+ var _react = _interopRequireDefault(require("react"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _reactQuill = _interopRequireDefault(require("react-quill"));
10
10
  require("react-quill/dist/quill.snow.css");
11
11
  var _styles = require("@mui/material/styles");
12
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
14
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
15
13
  const StyledReactQuill = (0, _styles.styled)(_reactQuill.default)(({
16
14
  theme
17
15
  }) => ({
@@ -22,20 +20,15 @@ const StyledReactQuill = (0, _styles.styled)(_reactQuill.default)(({
22
20
 
23
21
  /** Rich text editor for annotation body */
24
22
  function TextEditor({
25
- annoHtml,
26
- updateAnnotationBody
23
+ text,
24
+ setText
27
25
  }) {
28
- const [editorHtml, setEditorHtml] = (0, _react.useState)(annoHtml);
29
-
30
26
  /**
31
27
  * Handle Change On ReactQuil Editor
32
28
  * @param html
33
29
  */
34
30
  const handleChange = html => {
35
- setEditorHtml(html);
36
- if (updateAnnotationBody) {
37
- updateAnnotationBody(html);
38
- }
31
+ setText(html);
39
32
  };
40
33
  const modules = {
41
34
  toolbar: [[{
@@ -60,7 +53,7 @@ function TextEditor({
60
53
  return /*#__PURE__*/_react.default.createElement("div", {
61
54
  "data-text-editor": "name"
62
55
  }, /*#__PURE__*/_react.default.createElement(StyledReactQuill, {
63
- value: editorHtml,
56
+ value: text,
64
57
  onChange: handleChange,
65
58
  placeholder: "Your text here",
66
59
  bounds: "[data-text-editor=\"name\"]",
@@ -69,7 +62,7 @@ function TextEditor({
69
62
  }));
70
63
  }
71
64
  TextEditor.propTypes = {
72
- annoHtml: _propTypes.default.string.isRequired,
73
- updateAnnotationBody: _propTypes.default.func.isRequired
65
+ setText: _propTypes.default.func.isRequired,
66
+ text: _propTypes.default.string.isRequired
74
67
  };
75
68
  var _default = exports.default = TextEditor;
@@ -88,7 +88,7 @@ function AnnotationFormBody({
88
88
  saveAnnotation: saveAnnotation,
89
89
  t: t,
90
90
  windowId: windowId,
91
- commentTemplate: config?.annotation?.commentTemplate ?? '',
91
+ commentTemplate: config?.annotation?.commentTemplates ?? [],
92
92
  tagsSuggestions: config?.annotation?.tagsSuggestions ?? []
93
93
  })), debugMode && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Typography.default, null, playerReferences.getMediaType()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('scale'), ":", playerReferences.getScale()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('zoom'), ":", playerReferences.getZoom()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('image_true_size'), ":", playerReferences.getMediaTrueWidth(), ' ', "x", playerReferences.getMediaTrueHeight()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('container_size'), ":", playerReferences.getContainerWidth(), ' ', "x", playerReferences.getContainerHeight()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('image_displayed'), ":", playerReferences.getDisplayedMediaWidth(), ' ', "x", playerReferences.getDisplayedMediaHeight())));
94
94
  }
@@ -11,8 +11,8 @@ var _AnnotationFormFooter = _interopRequireDefault(require("./AnnotationFormFoot
11
11
  var _AnnotationFormUtils = require("./AnnotationFormUtils");
12
12
  var _TargetFormSection = _interopRequireDefault(require("./TargetFormSection"));
13
13
  var _KonvaUtils = require("./AnnotationFormOverlay/KonvaDrawing/KonvaUtils");
14
- var _TextFormSection = _interopRequireDefault(require("./TextFormSection"));
15
14
  var _MultiTagsInput = require("./MultiTagsInput");
15
+ var _TextCommentInput = require("./TextCommentInput");
16
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
17
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
18
18
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -39,7 +39,7 @@ function MultipleBodyTemplate({
39
39
  textBody: {
40
40
  purpose: 'describing',
41
41
  type: 'TextualBody',
42
- value: commentTemplate
42
+ value: ''
43
43
  }
44
44
  },
45
45
  motivation: 'commenting',
@@ -106,9 +106,10 @@ function MultipleBodyTemplate({
106
106
  spacing: 2
107
107
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
108
108
  item: true
109
- }, /*#__PURE__*/_react.default.createElement(_TextFormSection.default, {
110
- annoHtml: annotationState.maeData.textBody.value,
111
- updateAnnotationBody: updateAnnotationTextualBodyValue,
109
+ }, /*#__PURE__*/_react.default.createElement(_TextCommentInput.TextCommentInput, {
110
+ commentTemplates: commentTemplate,
111
+ comment: annotationState.maeData.textBody.value,
112
+ setComment: updateAnnotationTextualBodyValue,
112
113
  t: t
113
114
  })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
114
115
  item: true
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TextCommentInput = TextCommentInput;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _propTypes = _interopRequireDefault(require("prop-types"));
9
+ var _material = require("@mui/material");
10
+ var _creatable = _interopRequireDefault(require("react-select/creatable"));
11
+ var _TextEditor = _interopRequireDefault(require("../TextEditor"));
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ /**
14
+ * TextCommentInput component
15
+ * @param commentTemplates - The list of comment templates
16
+ * @param comment - The current comment
17
+ * @param setComment - Function to set the comment
18
+ * @param t - Translation function
19
+ * @constructor
20
+ */
21
+ function TextCommentInput({
22
+ commentTemplates,
23
+ comment,
24
+ setComment,
25
+ t
26
+ }) {
27
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Grid, {
28
+ container: true,
29
+ item: true
30
+ }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
31
+ variant: "formSectionTitle"
32
+ }, t('note'))), commentTemplates.length > 0 && /*#__PURE__*/_react.default.createElement(_material.Grid, {
33
+ item: true,
34
+ style: {
35
+ marginBottom: '10px'
36
+ }
37
+ }, /*#__PURE__*/_react.default.createElement(_creatable.default, {
38
+ options: commentTemplates.map(template => ({
39
+ label: template.title,
40
+ value: template.content,
41
+ title: template.content // Add title attribute for tooltip
42
+ })),
43
+ placeholder: t('useTemplate'),
44
+ onChange: selectedOption => {
45
+ if (selectedOption) {
46
+ setComment(selectedOption.value);
47
+ }
48
+ },
49
+ isClearable: true,
50
+ isSearchable: true,
51
+ formatOptionLabel: option => /*#__PURE__*/_react.default.createElement("div", {
52
+ title: option.title
53
+ }, option.label),
54
+ styles: {
55
+ marginBottom: '20px'
56
+ }
57
+ })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
58
+ container: true,
59
+ item: true
60
+ }, /*#__PURE__*/_react.default.createElement(_TextEditor.default, {
61
+ text: comment,
62
+ setText: setComment
63
+ })));
64
+ }
65
+ TextCommentInput.propTypes = {
66
+ comment: _propTypes.default.string.isRequired,
67
+ // eslint-disable-next-line react/forbid-prop-types
68
+ commentTemplates: _propTypes.default.arrayOf(_propTypes.default.object).isRequired,
69
+ setComment: _propTypes.default.func.isRequired,
70
+ t: _propTypes.default.func.isRequired
71
+ };
@@ -87,6 +87,7 @@ const en = exports.en = {
87
87
  textual_note_with_target: 'Textual note with target',
88
88
  tool_selection: 'Tool Selection',
89
89
  unsupported_media_message: 'Your current canvas media type is not supported by the annotation editor.',
90
+ useTemplate: 'Use a template',
90
91
  video_annotation_instruction: 'If you want to annotate video media, you must install MAEV to create and edit annotations on video:',
91
92
  your_tag_here: 'Your tag here:',
92
93
  zoom: 'Zoom'
@@ -87,6 +87,7 @@ const fr = exports.fr = {
87
87
  textual_note_with_target: 'Note textuelle avec cible',
88
88
  tool_selection: 'Sélection d’outil',
89
89
  unsupported_media_message: 'Le type de média de votre canvas actuel n\'est pas pris en charge par l\'éditeur d\'annotations.',
90
+ useTemplate: 'Utiliser un modèle',
90
91
  video_annotation_instruction: 'Si vous souhaitez annoter des vidéos, vous devez installer le plugin Mirador Annotation Editor Video (MAEV) pour créer et modifier des annotations sur les vidéos :',
91
92
  your_tag_here: 'Votre étiquette',
92
93
  zoom: 'Zoom'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mirador-annotation-editor-video",
3
- "version": "1.0.98",
3
+ "version": "1.1.0",
4
4
  "description": "Mirador annotation editor video plugin in a React component. Mirador 4 (Alpha 2) compatible ",
5
5
  "main": "es/index.js",
6
6
  "module": "es/index.js",
@@ -63,7 +63,7 @@
63
63
  "prop-types": "^15.7.2",
64
64
  "react": "^18.2.0",
65
65
  "react-dom": "^18.0.0",
66
- "uuid": "^8.0.0"
66
+ "uuid": "^11.0.0"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@babel/cli": "^7.25.9",
@@ -94,7 +94,7 @@
94
94
  "jest-canvas-mock": "^2.2.0",
95
95
  "jest-junit": "^15.0.0",
96
96
  "jest-localstorage-mock": "^2.4.2",
97
- "mirador": "npm:mirador-video@1.0.26",
97
+ "mirador": "npm:mirador-video@1.0.27",
98
98
  "prop-types": "^15.7.2",
99
99
  "react": "^18.2.0",
100
100
  "react-dom": "^18.0",
package/src/TextEditor.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import ReactQuill from 'react-quill';
4
4
  import 'react-quill/dist/quill.snow.css';
@@ -12,20 +12,15 @@ const StyledReactQuill = styled(ReactQuill)(({ theme }) => ({
12
12
 
13
13
  /** Rich text editor for annotation body */
14
14
  function TextEditor({
15
- annoHtml,
16
- updateAnnotationBody,
15
+ text,
16
+ setText,
17
17
  }) {
18
- const [editorHtml, setEditorHtml] = useState(annoHtml);
19
-
20
18
  /**
21
19
  * Handle Change On ReactQuil Editor
22
20
  * @param html
23
21
  */
24
22
  const handleChange = (html) => {
25
- setEditorHtml(html);
26
- if (updateAnnotationBody) {
27
- updateAnnotationBody(html);
28
- }
23
+ setText(html);
29
24
  };
30
25
  const modules = {
31
26
  toolbar: [
@@ -63,7 +58,7 @@ function TextEditor({
63
58
  return (
64
59
  <div data-text-editor="name">
65
60
  <StyledReactQuill
66
- value={editorHtml}
61
+ value={text}
67
62
  onChange={handleChange}
68
63
  placeholder="Your text here"
69
64
  bounds='[data-text-editor="name"]'
@@ -75,8 +70,8 @@ function TextEditor({
75
70
  }
76
71
 
77
72
  TextEditor.propTypes = {
78
- annoHtml: PropTypes.string.isRequired,
79
- updateAnnotationBody: PropTypes.func.isRequired,
73
+ setText: PropTypes.func.isRequired,
74
+ text: PropTypes.string.isRequired,
80
75
  };
81
76
 
82
77
  export default TextEditor;
@@ -112,7 +112,7 @@ export default function AnnotationFormBody(
112
112
  saveAnnotation={saveAnnotation}
113
113
  t={t}
114
114
  windowId={windowId}
115
- commentTemplate={config?.annotation?.commentTemplate ?? ''}
115
+ commentTemplate={config?.annotation?.commentTemplates ?? []}
116
116
  tagsSuggestions={config?.annotation?.tagsSuggestions ?? []}
117
117
  />
118
118
  )}
@@ -28,9 +28,6 @@ export function MultiTagsInput({
28
28
  <Typography variant="formSectionTitle">
29
29
  {t('tags')}
30
30
  </Typography>
31
- {/* Show list of suggestions into a clickable tag */}
32
- {/* add a toggle to show hide suggestions */}
33
-
34
31
  <CreatableSelect
35
32
  isMulti
36
33
  options={mappedSuggestionsTags}
@@ -39,11 +36,9 @@ export function MultiTagsInput({
39
36
  closeMenuOnSelect={false}
40
37
  placeholder={t('tagsPlaceholder')}
41
38
  />
42
-
43
39
  <Divider
44
40
  spacing={2}
45
41
  />
46
-
47
42
  </>
48
43
  );
49
44
  }
@@ -5,8 +5,8 @@ import AnnotationFormFooter from './AnnotationFormFooter';
5
5
  import { TEMPLATE } from './AnnotationFormUtils';
6
6
  import TargetFormSection from './TargetFormSection';
7
7
  import { resizeKonvaStage } from './AnnotationFormOverlay/KonvaDrawing/KonvaUtils';
8
- import TextFormSection from './TextFormSection';
9
8
  import { MultiTagsInput } from './MultiTagsInput';
9
+ import { TextCommentInput } from './TextCommentInput';
10
10
 
11
11
  /** Tagging Template* */
12
12
  export default function MultipleBodyTemplate(
@@ -34,7 +34,7 @@ export default function MultipleBodyTemplate(
34
34
  textBody: {
35
35
  purpose: 'describing',
36
36
  type: 'TextualBody',
37
- value: commentTemplate,
37
+ value: '',
38
38
  },
39
39
  },
40
40
  motivation: 'commenting',
@@ -108,9 +108,10 @@ export default function MultipleBodyTemplate(
108
108
  return (
109
109
  <Grid container direction="column" spacing={2}>
110
110
  <Grid item>
111
- <TextFormSection
112
- annoHtml={annotationState.maeData.textBody.value}
113
- updateAnnotationBody={updateAnnotationTextualBodyValue}
111
+ <TextCommentInput
112
+ commentTemplates={commentTemplate}
113
+ comment={annotationState.maeData.textBody.value}
114
+ setComment={updateAnnotationTextualBodyValue}
114
115
  t={t}
115
116
  />
116
117
  </Grid>
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Grid, Typography } from '@mui/material';
4
+ import CreatableSelect from 'react-select/creatable';
5
+ import TextEditor from '../TextEditor';
6
+
7
+ /**
8
+ * TextCommentInput component
9
+ * @param commentTemplates - The list of comment templates
10
+ * @param comment - The current comment
11
+ * @param setComment - Function to set the comment
12
+ * @param t - Translation function
13
+ * @constructor
14
+ */
15
+ export function TextCommentInput({
16
+ commentTemplates,
17
+ comment,
18
+ setComment,
19
+ t,
20
+ }) {
21
+ return (
22
+ <>
23
+ <Grid container item>
24
+ <Typography variant="formSectionTitle">
25
+ {t('note')}
26
+ </Typography>
27
+ </Grid>
28
+ {commentTemplates.length > 0 && (
29
+ <Grid item style={{ marginBottom: '10px' }}>
30
+ <CreatableSelect
31
+ options={commentTemplates.map((template) => ({
32
+ label: template.title,
33
+ value: template.content,
34
+ title: template.content, // Add title attribute for tooltip
35
+ }))}
36
+ placeholder={t('useTemplate')}
37
+ onChange={(selectedOption) => {
38
+ if (selectedOption) {
39
+ setComment(selectedOption.value);
40
+ }
41
+ }}
42
+ isClearable
43
+ isSearchable
44
+ formatOptionLabel={(option) => (
45
+ <div title={option.title}>
46
+ {option.label}
47
+ </div>
48
+ )}
49
+ styles={{
50
+ marginBottom: '20px',
51
+ }}
52
+ />
53
+ </Grid>
54
+ )}
55
+
56
+ <Grid container item>
57
+ <TextEditor
58
+ text={comment}
59
+ setText={setComment}
60
+ />
61
+ </Grid>
62
+ </>
63
+ );
64
+ }
65
+
66
+ TextCommentInput.propTypes = {
67
+ comment: PropTypes.string.isRequired,
68
+ // eslint-disable-next-line react/forbid-prop-types
69
+ commentTemplates: PropTypes.arrayOf(PropTypes.object).isRequired,
70
+ setComment: PropTypes.func.isRequired,
71
+ t: PropTypes.func.isRequired,
72
+ };
@@ -81,6 +81,7 @@ export const en = {
81
81
  textual_note_with_target: 'Textual note with target',
82
82
  tool_selection: 'Tool Selection',
83
83
  unsupported_media_message: 'Your current canvas media type is not supported by the annotation editor.',
84
+ useTemplate: 'Use a template',
84
85
  video_annotation_instruction: 'If you want to annotate video media, you must install MAEV to create and edit annotations on video:',
85
86
  your_tag_here: 'Your tag here:',
86
87
  zoom: 'Zoom',
@@ -81,6 +81,7 @@ export const fr = {
81
81
  textual_note_with_target: 'Note textuelle avec cible',
82
82
  tool_selection: 'Sélection d’outil',
83
83
  unsupported_media_message: 'Le type de média de votre canvas actuel n\'est pas pris en charge par l\'éditeur d\'annotations.',
84
+ useTemplate: 'Utiliser un modèle',
84
85
  video_annotation_instruction: 'Si vous souhaitez annoter des vidéos, vous devez installer le plugin Mirador Annotation Editor Video (MAEV) pour créer et modifier des annotations sur les vidéos :',
85
86
  your_tag_here: 'Votre étiquette',
86
87
  zoom: 'Zoom',