@searpent/react-image-annotate 2.0.74 → 2.0.76

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 (224) hide show
  1. package/.babelrc +6 -0
  2. package/.env +1 -0
  3. package/.flowconfig +2 -0
  4. package/.github/workflows/release-on-master.yml +32 -0
  5. package/.github/workflows/test.yml +16 -0
  6. package/.prettierrc +3 -0
  7. package/.releaserc.js +18 -0
  8. package/.storybook/addons.js +2 -0
  9. package/.storybook/config.js +16 -0
  10. package/LICENSE +21 -0
  11. package/package.json +1 -1
  12. package/public/favicon.ico +0 -0
  13. package/public/index.html +38 -0
  14. package/src/Annotator/bike-pic.png +0 -0
  15. package/src/Annotator/bike-pic2.png +0 -0
  16. package/src/Annotator/dab-keyframes.story.json +1 -0
  17. package/src/Annotator/exampleImages.js +48 -0
  18. package/src/Annotator/examplePhotos.js +7603 -0
  19. package/src/Annotator/index.js +380 -0
  20. package/src/Annotator/index.story.js +877 -0
  21. package/src/Annotator/poses.story.js +150 -0
  22. package/src/Annotator/reducers/combine-reducers.js +7 -0
  23. package/src/Annotator/reducers/convert-expanding-line-to-polygon.js +53 -0
  24. package/{Annotator → src/Annotator}/reducers/fix-twisted.js +5 -3
  25. package/src/Annotator/reducers/general-reducer.js +1228 -0
  26. package/src/Annotator/reducers/get-active-image.js +21 -0
  27. package/src/Annotator/reducers/get-implied-video-regions.js +115 -0
  28. package/src/Annotator/reducers/history-handler.js +60 -0
  29. package/src/Annotator/reducers/image-reducer.js +23 -0
  30. package/src/Annotator/reducers/video-reducer.js +85 -0
  31. package/src/Annotator/video.story.js +51 -0
  32. package/src/ClassSelectionMenu/index.js +112 -0
  33. package/src/Crosshairs/index.js +64 -0
  34. package/src/DebugSidebarBox/index.js +36 -0
  35. package/src/DemoSite/Editor.js +235 -0
  36. package/src/DemoSite/ErrorBoundaryDialog.js +34 -0
  37. package/src/DemoSite/index.js +41 -0
  38. package/src/DemoSite/index.story.js +10 -0
  39. package/src/DemoSite/simple-segmentation-example.json +572 -0
  40. package/{Editor → src/Editor}/annotation-plugin/annotation.css +2 -0
  41. package/src/Editor/annotation-plugin/annotation.js +536 -0
  42. package/src/Editor/index.js +50 -0
  43. package/src/Editor/readOnly.js +21 -0
  44. package/{Editor → src/Editor}/tools.js +3 -2
  45. package/src/Errorer/index.js +13 -0
  46. package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
  47. package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
  48. package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
  49. package/src/FullImageSegmentationAnnotator/index.js +7 -0
  50. package/src/FullImageSegmentationAnnotator/index.story.js +177 -0
  51. package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
  52. package/src/GroupSelectorSidebarBox/index.js +48 -0
  53. package/src/GroupsEditorSidebarBox/index.js +108 -0
  54. package/src/HelpSidebarBox/index.js +43 -0
  55. package/src/HighlightBox/index.js +143 -0
  56. package/src/HistorySidebarBox/index.js +78 -0
  57. package/src/ImageCanvas/dancing-man.story.jpg +0 -0
  58. package/src/ImageCanvas/index.js +515 -0
  59. package/src/ImageCanvas/index.story.js +314 -0
  60. package/src/ImageCanvas/mouse_mask.story.png +0 -0
  61. package/src/ImageCanvas/region-tools.js +171 -0
  62. package/src/ImageCanvas/seves_desk.story.jpg +0 -0
  63. package/{ImageCanvas → src/ImageCanvas}/styles.js +8 -12
  64. package/src/ImageCanvas/use-mouse.js +168 -0
  65. package/src/ImageCanvas/use-project-box.js +23 -0
  66. package/src/ImageCanvas/use-wasd-mode.js +50 -0
  67. package/src/ImageMask/index.js +127 -0
  68. package/src/ImageMask/load-image.js +32 -0
  69. package/src/ImageSelectorSidebarBox/index.js +54 -0
  70. package/src/KeyframeTimeline/get-time-string.js +25 -0
  71. package/src/KeyframeTimeline/index.js +223 -0
  72. package/src/KeyframesSelectorSidebarBox/index.js +93 -0
  73. package/src/LandingPage/content.md +57 -0
  74. package/src/LandingPage/github-markdown.css +964 -0
  75. package/src/LandingPage/index.js +147 -0
  76. package/src/Locker/index.js +13 -0
  77. package/src/MainLayout/RightSidebarItemsWrapper.js +21 -0
  78. package/src/MainLayout/icon-dictionary.js +79 -0
  79. package/src/MainLayout/index.js +564 -0
  80. package/src/MainLayout/index.story.js +240 -0
  81. package/{MainLayout → src/MainLayout}/styles.js +7 -6
  82. package/src/MainLayout/types.js +171 -0
  83. package/src/MainLayout/use-implied-video-regions.js +17 -0
  84. package/src/MetadataEditorSidebarBox/index.js +160 -0
  85. package/src/PageSelector/index.js +159 -0
  86. package/src/PointDistances/index.js +90 -0
  87. package/src/PreventScrollToParents/index.js +48 -0
  88. package/src/PreventScrollToParents/index.story.js +23 -0
  89. package/src/RegionLabel/index.js +236 -0
  90. package/{RegionLabel → src/RegionLabel}/styles.js +15 -12
  91. package/src/RegionSelectAndTransformBoxes/index.js +236 -0
  92. package/src/RegionSelectorSidebarBox/index.js +220 -0
  93. package/{RegionSelectorSidebarBox → src/RegionSelectorSidebarBox}/styles.js +14 -13
  94. package/src/RegionShapes/index.js +254 -0
  95. package/src/RegionTags/index.js +136 -0
  96. package/src/SettingsDialog/index.js +58 -0
  97. package/src/SettingsProvider/index.js +57 -0
  98. package/src/Shortcuts/ShortcutField.js +44 -0
  99. package/src/Shortcuts/index.js +129 -0
  100. package/src/ShortcutsManager/index.js +162 -0
  101. package/src/Sidebar/index.js +117 -0
  102. package/src/SidebarBoxContainer/index.js +93 -0
  103. package/src/SmallToolButton/index.js +57 -0
  104. package/src/TagsSidebarBox/index.js +93 -0
  105. package/src/TaskDescriptionSidebarBox/index.js +43 -0
  106. package/src/Theme/index.js +36 -0
  107. package/src/VideoOrImageCanvasBackground/index.js +170 -0
  108. package/src/colors.js +32 -0
  109. package/src/hooks/use-colors.js +75 -0
  110. package/src/hooks/use-event-callback.js +11 -0
  111. package/src/hooks/use-exclude-pattern.js +27 -0
  112. package/src/hooks/use-load-image.js +21 -0
  113. package/src/hooks/use-window-size.js +46 -0
  114. package/{hooks → src/hooks}/xpattern.js +1 -1
  115. package/src/hooks/xpattern.png +0 -0
  116. package/src/index.js +18 -0
  117. package/src/lib.js +7 -0
  118. package/src/screenshot.png +0 -0
  119. package/src/site.css +5 -0
  120. package/src/stories.js +2 -0
  121. package/src/utils/blocks-to-article.js +61 -0
  122. package/{utils → src/utils}/blocks-to-article.test.js +8 -5
  123. package/{utils → src/utils}/default-locked-until.js +1 -2
  124. package/{utils → src/utils}/filter-only-unique.js +1 -1
  125. package/src/utils/get-from-local-storage.js +7 -0
  126. package/src/utils/get-hotkey-help-text.js +11 -0
  127. package/src/utils/get-landmarks-with-transform.js +23 -0
  128. package/src/utils/photosToImages.js +67 -0
  129. package/src/utils/regions-groups.js +19 -0
  130. package/src/utils/regions-to-blocks.js +16 -0
  131. package/src/utils/saveable-actions-enum.js +5 -0
  132. package/src/utils/set-in-local-storage.js +6 -0
  133. package/src/utils/sleep.js +3 -0
  134. package/src/utils/uuid-to-hash.js +5 -0
  135. package/Annotator/exampleImages.js +0 -41
  136. package/Annotator/examplePhotos.js +0 -6980
  137. package/Annotator/index.js +0 -417
  138. package/Annotator/reducers/combine-reducers.js +0 -14
  139. package/Annotator/reducers/convert-expanding-line-to-polygon.js +0 -73
  140. package/Annotator/reducers/general-reducer.js +0 -1430
  141. package/Annotator/reducers/get-active-image.js +0 -27
  142. package/Annotator/reducers/get-implied-video-regions.js +0 -180
  143. package/Annotator/reducers/history-handler.js +0 -38
  144. package/Annotator/reducers/image-reducer.js +0 -20
  145. package/Annotator/reducers/video-reducer.js +0 -88
  146. package/ClassSelectionMenu/index.js +0 -140
  147. package/Crosshairs/index.js +0 -53
  148. package/DebugSidebarBox/index.js +0 -20
  149. package/DemoSite/Editor.js +0 -194
  150. package/DemoSite/ErrorBoundaryDialog.js +0 -64
  151. package/DemoSite/index.js +0 -40
  152. package/Editor/annotation-plugin/annotation.js +0 -642
  153. package/Editor/index.js +0 -93
  154. package/Editor/readOnly.js +0 -68
  155. package/Errorer/index.js +0 -11
  156. package/FullImageSegmentationAnnotator/index.js +0 -7
  157. package/GroupSelectorSidebarBox/index.js +0 -63
  158. package/GroupsEditorSidebarBox/index.js +0 -138
  159. package/HelpSidebarBox/index.js +0 -58
  160. package/HighlightBox/index.js +0 -102
  161. package/HistorySidebarBox/index.js +0 -71
  162. package/ImageCanvas/index.js +0 -441
  163. package/ImageCanvas/region-tools.js +0 -165
  164. package/ImageCanvas/use-mouse.js +0 -180
  165. package/ImageCanvas/use-project-box.js +0 -27
  166. package/ImageCanvas/use-wasd-mode.js +0 -62
  167. package/ImageMask/index.js +0 -133
  168. package/ImageMask/load-image.js +0 -25
  169. package/ImageSelectorSidebarBox/index.js +0 -60
  170. package/KeyframeTimeline/get-time-string.js +0 -27
  171. package/KeyframeTimeline/index.js +0 -233
  172. package/KeyframesSelectorSidebarBox/index.js +0 -93
  173. package/LandingPage/index.js +0 -159
  174. package/Locker/index.js +0 -11
  175. package/MainLayout/RightSidebarItemsWrapper.js +0 -19
  176. package/MainLayout/icon-dictionary.js +0 -104
  177. package/MainLayout/index.js +0 -526
  178. package/MainLayout/types.js +0 -0
  179. package/MainLayout/use-implied-video-regions.js +0 -13
  180. package/MetadataEditorSidebarBox/index.js +0 -231
  181. package/PageSelector/index.js +0 -180
  182. package/PointDistances/index.js +0 -73
  183. package/PreventScrollToParents/index.js +0 -51
  184. package/RegionLabel/index.js +0 -232
  185. package/RegionSelectAndTransformBoxes/index.js +0 -169
  186. package/RegionSelectorSidebarBox/index.js +0 -254
  187. package/RegionShapes/index.js +0 -294
  188. package/RegionTags/index.js +0 -144
  189. package/SettingsDialog/index.js +0 -52
  190. package/SettingsProvider/index.js +0 -60
  191. package/Shortcuts/ShortcutField.js +0 -46
  192. package/Shortcuts/index.js +0 -133
  193. package/ShortcutsManager/index.js +0 -155
  194. package/Sidebar/index.js +0 -69
  195. package/SidebarBoxContainer/index.js +0 -93
  196. package/SmallToolButton/index.js +0 -42
  197. package/TagsSidebarBox/index.js +0 -105
  198. package/TaskDescriptionSidebarBox/index.js +0 -58
  199. package/Theme/index.js +0 -30
  200. package/VideoOrImageCanvasBackground/index.js +0 -151
  201. package/colors.js +0 -14
  202. package/hooks/use-colors.js +0 -94
  203. package/hooks/use-event-callback.js +0 -10
  204. package/hooks/use-exclude-pattern.js +0 -24
  205. package/hooks/use-load-image.js +0 -26
  206. package/hooks/use-window-size.js +0 -46
  207. package/index.js +0 -3
  208. package/lib.js +0 -3
  209. package/stories.js +0 -5
  210. package/utils/blocks-to-article.js +0 -60
  211. package/utils/get-from-local-storage.js +0 -7
  212. package/utils/get-hotkey-help-text.js +0 -9
  213. package/utils/get-landmarks-with-transform.js +0 -40
  214. package/utils/photosToImages.js +0 -85
  215. package/utils/regions-groups.js +0 -28
  216. package/utils/regions-to-blocks.js +0 -18
  217. package/utils/saveable-actions-enum.js +0 -3
  218. package/utils/set-in-local-storage.js +0 -3
  219. package/utils/sleep.js +0 -7
  220. package/utils/uuid-to-hash.js +0 -5
  221. /package/{Errorer → src/Errorer}/errorer.css +0 -0
  222. /package/{Locker → src/Locker}/locker.css +0 -0
  223. /package/{PageSelector → src/PageSelector}/page-selector.css +0 -0
  224. /package/{utils → src/utils}/next-group-id.js +0 -0
@@ -0,0 +1,536 @@
1
+ /**
2
+ * Build styles
3
+ */
4
+ import './annotation.css';
5
+
6
+ export function whitespaceCharactersToHTML(str = '') {
7
+ return str
8
+ // new line whitespace
9
+ .replaceAll(/[ ]\n[ ]/gm, '&nbsp;<br>&nbsp;') // space both sides adds &nbsp;
10
+ .replaceAll(/\n[ ]/gm, '<br>&nbsp;') // space right side adds &nbsp;
11
+ .replaceAll(/[ ]\n/gm, '&nbsp;<br>') // space left side adds &nbsp;
12
+ .replaceAll(/\n/gm, '<br>') // no spaces
13
+ // tab whitespace
14
+ .replaceAll(/\t/gm, '&nbsp;&nbsp;&nbsp;&nbsp;') // no spaces
15
+ }
16
+
17
+ function HTMLToWhitespaceCharacters(str = '') {
18
+ return str
19
+ .replaceAll(/((&nbsp;|\s){4})/gm, '\t')
20
+ .replaceAll('&nbsp;', ' ')
21
+ .replaceAll('<br>', '\n') // new line whitespace
22
+ }
23
+
24
+
25
+ // Possible classes
26
+ // ================
27
+
28
+ class Annotation {
29
+ /**
30
+ * Render plugin`s main Element and fill it with saved data
31
+ *
32
+ * @param {{data: HeaderData, config: HeaderConfig, api: object}}
33
+ * data — previously saved data
34
+ * config - user config for Tool
35
+ * api - Editor.js API
36
+ * readOnly - read only mode flag
37
+ */
38
+ constructor({ data, config, api, readOnly }) {
39
+ this.api = api;
40
+ this.readOnly = readOnly;
41
+
42
+ /**
43
+ * Styles
44
+ *
45
+ * @type {object}
46
+ */
47
+ this._CSS = {
48
+ block: this.api.styles.block,
49
+ settingsButton: this.api.styles.settingsButton,
50
+ settingsButtonActive: this.api.styles.settingsButtonActive,
51
+ wrapper: 'ce-header',
52
+ backgroundColor: (data?.highlighted && data?.clsColor) ? data.clsColor : undefined,
53
+ };
54
+
55
+ /**
56
+ * Tool's settings passed from Editor
57
+ *
58
+ * @type {HeaderConfig}
59
+ * @private
60
+ */
61
+ this._settings = config;
62
+
63
+ /**
64
+ * Block's data
65
+ *
66
+ * @type {HeaderData}
67
+ * @private
68
+ */
69
+ this._data = this.normalizeData(data);
70
+
71
+ /**
72
+ * List of settings buttons
73
+ *
74
+ * @type {HTMLElement[]}
75
+ */
76
+ this.settingsButtons = [];
77
+
78
+ /**
79
+ * Main Block wrapper
80
+ *
81
+ * @type {HTMLElement}
82
+ * @private
83
+ */
84
+ this._element = this.getTag();
85
+ }
86
+
87
+ /**
88
+ * Normalize input data
89
+ *
90
+ * @param {HeaderData} data - saved data to process
91
+ *
92
+ * @returns {HeaderData}
93
+ * @private
94
+ */
95
+ normalizeData(data) {
96
+ const newData = {};
97
+
98
+ if (typeof data !== 'object') {
99
+ data = {};
100
+ }
101
+
102
+ newData.text = whitespaceCharactersToHTML(data.text)
103
+ newData.labelName = data.labelName || this.defaultLabel.labelName;
104
+
105
+ return newData;
106
+ }
107
+
108
+ /**
109
+ * Return Tool's view
110
+ *
111
+ * @returns {HTMLHeadingElement}
112
+ * @public
113
+ */
114
+ render() {
115
+ return this._element;
116
+ }
117
+
118
+ /**
119
+ * Create Block's settings block
120
+ *
121
+ * @returns {HTMLElement}
122
+ */
123
+ renderSettings() {
124
+ const holder = document.createElement('DIV');
125
+
126
+ // do not add settings button, when only one label is configured
127
+ if (this.labels.length <= 1) {
128
+ return holder;
129
+ }
130
+
131
+ /** Add type selectors */
132
+ this.labels.forEach(label => {
133
+ const selectTypeButton = document.createElement('DIV');
134
+
135
+ selectTypeButton.classList.add(this._CSS.settingsButton);
136
+
137
+ /**
138
+ * Highlight current label button
139
+ */
140
+ if (this.currentLabel.labelName === label.labelName) {
141
+ selectTypeButton.classList.add(this._CSS.settingsButtonActive);
142
+ }
143
+
144
+ /**
145
+ * Add SVG icon
146
+ */
147
+ selectTypeButton.innerHTML = `${label.labelName}`;
148
+
149
+ /**
150
+ * Save label to its button
151
+ */
152
+ selectTypeButton.dataset.labelName = label.labelName;
153
+
154
+ /**
155
+ * Set up click handler
156
+ */
157
+ selectTypeButton.addEventListener('click', () => {
158
+ this.setLabelName(label.labelName);
159
+ });
160
+
161
+ /**
162
+ * Append settings button to holder
163
+ */
164
+ holder.appendChild(selectTypeButton);
165
+
166
+ /**
167
+ * Save settings buttons
168
+ */
169
+ this.settingsButtons.push(selectTypeButton);
170
+ });
171
+
172
+ return holder;
173
+ }
174
+
175
+ /**
176
+ * Callback for Block's settings buttons
177
+ *
178
+ * @param {labelName} labelName - labelName to set
179
+ */
180
+ setLabelName(labelName) {
181
+ this.data = {
182
+ labelName,
183
+ text: this.data.text
184
+ };
185
+
186
+ /**
187
+ * Highlight button by selected labelName
188
+ */
189
+ this.settingsButtons.forEach(button => {
190
+ button.classList.toggle(
191
+ this._CSS.settingsButtonActive,
192
+ button.dataset.labelName === labelName
193
+ );
194
+ });
195
+ }
196
+
197
+ /**
198
+ * Method that specified how to merge two Text blocks.
199
+ * Called by Editor.js by backspace at the beginning of the Block
200
+ *
201
+ * @param {HeaderData} data - saved data to merger with current block
202
+ * @public
203
+ */
204
+ merge(data) {
205
+ const newData = {
206
+ text: this.data.text + data.text,
207
+ labelName: this.data.labelName
208
+ };
209
+
210
+ this.data = newData;
211
+ }
212
+
213
+ /**
214
+ * Validate Text block data:
215
+ * - check for emptiness
216
+ *
217
+ * @param {HeaderData} blockData — data received after saving
218
+ * @returns {boolean} false if saved data is not correct, otherwise true
219
+ * @public
220
+ */
221
+ validate(blockData) {
222
+ return blockData.text.trim() !== '';
223
+ }
224
+
225
+ /**
226
+ * Extract Tool's data from the view
227
+ *
228
+ * @param {HTMLHeadingElement} toolsContent - Text tools rendered view
229
+ * @returns {HeaderData} - saved data
230
+ * @public
231
+ */
232
+ save(toolsContent) {
233
+ return {
234
+ text: HTMLToWhitespaceCharacters(toolsContent.innerHTML),
235
+ labelName: this.currentLabel.labelName
236
+ };
237
+ }
238
+
239
+ /**
240
+ * Allow Header to be converted to/from other blocks
241
+ */
242
+ static get conversionConfig() {
243
+ return {
244
+ export: 'text', // use 'text' property for other blocks
245
+ import: 'text' // fill 'text' property from other block's export string
246
+ };
247
+ }
248
+
249
+ /**
250
+ * Sanitizer Rules
251
+ */
252
+ static get sanitize() {
253
+ return {
254
+ labelName: false,
255
+ text: {}
256
+ };
257
+ }
258
+
259
+ /**
260
+ * Returns true to notify core that read-only is supported
261
+ *
262
+ * @returns {boolean}
263
+ */
264
+ static get isReadOnlySupported() {
265
+ return true;
266
+ }
267
+
268
+ /**
269
+ * Get current Tools`s data
270
+ *
271
+ * @returns {HeaderData} Current data
272
+ * @private
273
+ */
274
+ get data() {
275
+ this._data.text = this._element.innerHTML;
276
+ this._data.labelName = this.currentLabel.labelName;
277
+
278
+ return this._data;
279
+ }
280
+
281
+ /**
282
+ * Store data in plugin:
283
+ * - at the this._data property
284
+ * - at the HTML
285
+ *
286
+ * @param {HeaderData} data — data to set
287
+ * @private
288
+ */
289
+ set data(data) {
290
+ this._data = this.normalizeData(data);
291
+
292
+ /**
293
+ * If labelName is set and block in DOM
294
+ * then replace it to a new block
295
+ */
296
+ if (data.labelName !== undefined && this._element.parentNode) {
297
+ /**
298
+ * Create a new tag
299
+ *
300
+ * @type {HTMLHeadingElement}
301
+ */
302
+ const newHeader = this.getTag();
303
+
304
+ /**
305
+ * Save Block's content
306
+ */
307
+ newHeader.innerHTML = this._element.innerHTML;
308
+
309
+ /**
310
+ * Replace blocks
311
+ */
312
+ this._element.parentNode.replaceChild(newHeader, this._element);
313
+
314
+ /**
315
+ * Save new block to private variable
316
+ *
317
+ * @type {HTMLHeadingElement}
318
+ * @private
319
+ */
320
+ this._element = newHeader;
321
+ }
322
+
323
+ /**
324
+ * If data.text was passed then update block's content
325
+ */
326
+ if (data.text !== undefined) {
327
+ this._element.innerHTML = this._data.text || '';
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Get tag for target label
333
+ * By default returns second-labelled header
334
+ *
335
+ * @returns {HTMLElement}
336
+ */
337
+ getTag() {
338
+ /**
339
+ * Create element for current Block's label
340
+ */
341
+ const tag = document.createElement(this.currentLabel.tag);
342
+ if (this._CSS.backgroundColor) {
343
+ tag.style.backgroundColor = this._CSS.backgroundColor
344
+ }
345
+
346
+ /**
347
+ * Add text to block
348
+ */
349
+ tag.innerHTML = this._data.text || '';
350
+
351
+ /**
352
+ * Add styles class
353
+ */
354
+ tag.classList.add(this._CSS.wrapper);
355
+
356
+ /**
357
+ * Make tag editable
358
+ */
359
+ tag.contentEditable = this.readOnly ? 'false' : 'true';
360
+
361
+ /**
362
+ * Add Placeholder
363
+ */
364
+ tag.dataset.placeholder = this.api.i18n.t(this._settings.placeholder || '');
365
+
366
+ return tag;
367
+ }
368
+
369
+ /**
370
+ * Get current label
371
+ *
372
+ * @returns {label}
373
+ */
374
+ get currentLabel() {
375
+ let label = this.labels.find(
376
+ labelItem => labelItem.labelName === this._data.labelName
377
+ );
378
+
379
+ if (!label) {
380
+ label = this.defaultLabel;
381
+ }
382
+
383
+ return label;
384
+ }
385
+
386
+ /**
387
+ * Return default label
388
+ *
389
+ * @returns {label}
390
+ */
391
+ get defaultLabel() {
392
+ /**
393
+ * User can specify own default label value
394
+ */
395
+ if (this._settings.defaultLabel) {
396
+ const userSpecified = this.labels.find(labelItem => {
397
+ return labelItem.labelName === this._settings.defaultLabel;
398
+ });
399
+
400
+ if (userSpecified) {
401
+ return userSpecified;
402
+ }
403
+ console.warn(
404
+ "(ง'̀-'́)ง Annotation Tool: the default label specified was not found in available labels"
405
+ );
406
+ }
407
+
408
+ /**
409
+ * With no additional options, there will be H2 by default
410
+ *
411
+ * @type {label}
412
+ */
413
+ return this.labels[1];
414
+ }
415
+
416
+ /**
417
+ * @typedef {object} label
418
+ * @property {labelName} labelName - label labelName
419
+ * @property {string} tag - tag corresponds with label labelName
420
+ * @property {string} svg - icon
421
+ */
422
+
423
+ /**
424
+ * Available header labels
425
+ *
426
+ * @returns {label[]}
427
+ */
428
+ get labels() {
429
+ const availableLabels = [
430
+ {
431
+ labelName: 'title',
432
+ tag: 'h1',
433
+ name: 'title',
434
+ backgroundColor: '#ffcccc'
435
+ },
436
+ { labelName: 'subtitle', tag: 'h2', name: 'subtitle', backgroundColor: '#ffccff' },
437
+ { labelName: 'text', tag: 'p', name: 'text', backgroundColor: '#14deef' },
438
+ { labelName: 'author', tag: 'i', name: 'author', backgroundColor: '#00bb00' },
439
+ { labelName: 'appendix', tag: 'p', name: 'appendix', backgroundColor: '#dcfcec' },
440
+ { labelName: 'photo_author', tag: 'p', name: 'photo_author', backgroundColor: '#bb0000' },
441
+ { labelName: 'photo_caption', tag: 'p', name: 'photo_caption', backgroundColor: '#ccffff' },
442
+ { labelName: 'advertisement', tag: 'p', name: 'advertisement', backgroundColor: '#ffeccc' },
443
+ { labelName: 'other_graphics', tag: 'p', name: 'other_graphics', backgroundColor: '#ff5400' },
444
+ { labelName: 'unknown', tag: 's', name: 'unknown', backgroundColor: '#cccccc' },
445
+ { labelName: 'about_author', tag: 'p', name: 'about_author', backgroundColor: '#ecffec' },
446
+ { labelName: 'image', tag: 'p', name: 'image', backgroundColor: '#ffffcc' },
447
+ { labelName: 'interview', tag: 'p', name: 'interview', backgroundColor: '#23b20f' },
448
+ { labelName: 'table', tag: 'p', name: 'table', backgroundColor: '#0000bb' },
449
+ { labelName: 'section', tag: 'p', name: 'section', backgroundColor: '#ffcccc' }
450
+ ];
451
+
452
+ return this._settings.labels
453
+ ? availableLabels.filter(l => this._settings.labels.includes(l.labelName))
454
+ : availableLabels;
455
+ }
456
+
457
+ /**
458
+ * Handle H1-H6 tags on paste to substitute it with header Tool
459
+ *
460
+ * @param {PasteEvent} event - event with pasted content
461
+ */
462
+ onPaste(event) {
463
+ const content = event.detail.data;
464
+
465
+ /**
466
+ * Define default label value
467
+ *
468
+ * @type {labelName}
469
+ */
470
+ let { labelName } = this.defaultLabel;
471
+
472
+ switch (content.tagName) {
473
+ case 'H1':
474
+ labelName = 1;
475
+ break;
476
+ case 'H2':
477
+ labelName = 2;
478
+ break;
479
+ case 'H3':
480
+ labelName = 3;
481
+ break;
482
+ case 'H4':
483
+ labelName = 4;
484
+ break;
485
+ case 'H5':
486
+ labelName = 5;
487
+ break;
488
+ case 'H6':
489
+ labelName = 6;
490
+ break;
491
+ }
492
+
493
+ // if (this._settings.labels) {
494
+ // // Fallback to nearest label when specified not available
495
+ // label = this._settings.labels.reduce((prevLabel, currLabel) => {
496
+ // return Math.abs(currLabel - label) < Math.abs(prevLabel - label)
497
+ // ? currLabel
498
+ // : prevLabel;
499
+ // });
500
+ // }
501
+
502
+ this.data = {
503
+ labelName,
504
+ text: content.innerHTML
505
+ };
506
+ }
507
+
508
+ /**
509
+ * Used by Editor.js paste handling API.
510
+ * Provides configuration to handle H1-H6 tags.
511
+ *
512
+ * @returns {{handler: (function(HTMLElement): {text: string}), tags: string[]}}
513
+ */
514
+ static get pasteConfig() {
515
+ return {
516
+ tags: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6']
517
+ };
518
+ }
519
+
520
+ /**
521
+ * Get Tool toolbox settings
522
+ * icon - Tool icon's SVG
523
+ * title - title to show in toolbox
524
+ *
525
+ * @returns {{icon: string, title: string}}
526
+ */
527
+ static get toolbox() {
528
+ return {
529
+ icon:
530
+ '<svg width="17" height="15" viewBox="0 0 336 276" xmlns="http://www.w3.org/2000/svg"><path d="M291 150V79c0-19-15-34-34-34H79c-19 0-34 15-34 34v42l67-44 81 72 56-29 42 30zm0 52l-43-30-56 30-81-67-66 39v23c0 19 15 34 34 34h178c17 0 31-13 34-29zM79 0h178c44 0 79 35 79 79v118c0 44-35 79-79 79H79c-44 0-79-35-79-79V79C0 35 35 0 79 0z"/></svg>',
531
+ title: 'Annotation'
532
+ };
533
+ }
534
+ }
535
+
536
+ export default Annotation;
@@ -0,0 +1,50 @@
1
+ import React, { useState } from 'react';
2
+ import { createReactEditorJS } from 'react-editor-js'
3
+ import blocksToArticle from '../utils/blocks-to-article';
4
+ import { EDITOR_JS_TOOLS } from './tools'
5
+ import ReadOnly from './readOnly';
6
+
7
+ const ReactEditorJS = createReactEditorJS()
8
+
9
+ function Editor({ blocks = [], onChange, imageIndex, selectedFrame }) {
10
+ const [editMode, setEditMode] = useState(false);
11
+ const handleChange = async instance => {
12
+ const data = await instance.saver.save();
13
+ onChange({ imageIndex, data })
14
+ };
15
+ const toggleEditMode = () => {
16
+ setEditMode(prev => !prev)
17
+ }
18
+
19
+ if (blocks.length < 1) {
20
+ return <div className='instructions'><h1>Click article to display text.</h1></div>
21
+ }
22
+
23
+ return (
24
+ <div>
25
+ <div className="show-metadata-wrapper">
26
+ <label className="switch mr-2">
27
+ <input id="show-metadata" type="checkbox" value={editMode} onChange={toggleEditMode} />
28
+ <span className="slider round"></span>
29
+ </label>
30
+ <label>Edit mode</label>
31
+ </div>
32
+
33
+ {
34
+ !editMode ?
35
+ (<ReadOnly article={blocksToArticle(blocks)} />) :
36
+ (<ReactEditorJS defaultValue={{
37
+ blocks
38
+ }}
39
+ tools={EDITOR_JS_TOOLS}
40
+ onChange={handleChange}
41
+ enableReInitialize
42
+ key={selectedFrame}
43
+ />)
44
+ }
45
+ </div>
46
+
47
+ );
48
+ }
49
+
50
+ export default Editor;
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+
3
+ function ReadOnly({ article }) {
4
+ return (<div>
5
+ <h1 className='ro-title' dangerouslySetInnerHTML={{ __html: article.title }} />
6
+ <h2 className='ro-subtitle' dangerouslySetInnerHTML={{ __html: article.subtitle }} />
7
+ <p className='ro-text' dangerouslySetInnerHTML={{ __html: article.text }}></p>
8
+ <p className='ro-author' dangerouslySetInnerHTML={{ __html: article.author }}></p>
9
+ <p className='ro-about-author' dangerouslySetInnerHTML={{ __html: article.about_author }}></p>
10
+ <p className='ro-appendix' dangerouslySetInnerHTML={{ __html: article.appendix }}></p>
11
+ <p className='ro-photo-author' dangerouslySetInnerHTML={{ __html: article.photo_author }}></p>
12
+ <p className='ro-photo-caption' dangerouslySetInnerHTML={{ __html: article.photo_caption }}></p>
13
+ <p className='ro-advertisment' dangerouslySetInnerHTML={{ __html: article.advertisement }}></p>
14
+ <p className='ro-other-graphics' dangerouslySetInnerHTML={{ __html: article.other_graphics }}></p>
15
+ <p className='ro-unknown' dangerouslySetInnerHTML={{ __html: article.unknown }}></p>
16
+ <p className='ro-table' dangerouslySetInnerHTML={{ __html: article.table }}></p>
17
+ <p className='ro-section' dangerouslySetInnerHTML={{ __html: article.section }}></p>
18
+ </div>)
19
+ }
20
+
21
+ export default ReadOnly;
@@ -1,5 +1,6 @@
1
1
  // tools.js
2
2
  import Annotation from './annotation-plugin/annotation';
3
- export var EDITOR_JS_TOOLS = {
3
+
4
+ export const EDITOR_JS_TOOLS = {
4
5
  annotation: Annotation
5
- };
6
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import ErrorIcon from '@mui/icons-material/Error';
3
+ import './errorer.css';
4
+
5
+ function Errorer() {
6
+ return (
7
+ <div className="errorer">
8
+ <ErrorIcon />
9
+ </div>
10
+ );
11
+ }
12
+
13
+ export default Errorer;
@@ -0,0 +1,7 @@
1
+ // @flow
2
+ import React from "react"
3
+ import Annotator from "../Annotator"
4
+
5
+ export default (props) => {
6
+ return <Annotator {...props} fullImageSegmentationMode={true} />
7
+ }