@searpent/react-image-annotate 2.1.0 → 2.1.1
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/Annotator/examplePhotos.js +4 -76
- package/Annotator/index.js +2 -94
- package/Annotator/reducers/general-reducer.js +5 -23
- package/Editor/editor.css +30 -0
- package/package.json +2 -2
|
@@ -750,68 +750,8 @@ var examplePhotos = [{
|
|
|
750
750
|
"Y1": 0,
|
|
751
751
|
"Y2": 1
|
|
752
752
|
},
|
|
753
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\"
|
|
754
|
-
"groupId": "
|
|
755
|
-
"id": "metadata-0"
|
|
756
|
-
}, {
|
|
757
|
-
"label": "metadata",
|
|
758
|
-
"score": 1,
|
|
759
|
-
"box": {
|
|
760
|
-
"X1": 0,
|
|
761
|
-
"X2": 1,
|
|
762
|
-
"Y1": 0,
|
|
763
|
-
"Y2": 1
|
|
764
|
-
},
|
|
765
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\",\"metadataId\":\"articleType-1\"}, {\"key\":\"section\",\"value\":\"editorial\",\"metadataId\":\"section-1\"}]",
|
|
766
|
-
"groupId": "1",
|
|
767
|
-
"id": "metadata-1"
|
|
768
|
-
}, {
|
|
769
|
-
"label": "metadata",
|
|
770
|
-
"score": 1,
|
|
771
|
-
"box": {
|
|
772
|
-
"X1": 0,
|
|
773
|
-
"X2": 1,
|
|
774
|
-
"Y1": 0,
|
|
775
|
-
"Y2": 1
|
|
776
|
-
},
|
|
777
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\",\"metadataId\":\"articleType-2\"}, {\"key\":\"section\",\"value\":\"editorial\",\"metadataId\":\"section-2\"}]",
|
|
778
|
-
"groupId": "2",
|
|
779
|
-
"id": "metadata-2"
|
|
780
|
-
}, {
|
|
781
|
-
"label": "metadata",
|
|
782
|
-
"score": 1,
|
|
783
|
-
"box": {
|
|
784
|
-
"X1": 0,
|
|
785
|
-
"X2": 1,
|
|
786
|
-
"Y1": 0,
|
|
787
|
-
"Y2": 1
|
|
788
|
-
},
|
|
789
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\",\"metadataId\":\"articleType-3\"}, {\"key\":\"section\",\"value\":\"editorial\",\"metadataId\":\"section-3\"}]",
|
|
790
|
-
"groupId": "3",
|
|
791
|
-
"id": "metadata-3"
|
|
792
|
-
}, {
|
|
793
|
-
"label": "metadata",
|
|
794
|
-
"score": 1,
|
|
795
|
-
"box": {
|
|
796
|
-
"X1": 0,
|
|
797
|
-
"X2": 1,
|
|
798
|
-
"Y1": 0,
|
|
799
|
-
"Y2": 1
|
|
800
|
-
},
|
|
801
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\",\"metadataId\":\"articleType-4\"}, {\"key\":\"section\",\"value\":\"editorial\",\"metadataId\":\"section-4\"}]",
|
|
802
|
-
"groupId": "4",
|
|
803
|
-
"id": "metadata-4"
|
|
804
|
-
}, {
|
|
805
|
-
"label": "metadata",
|
|
806
|
-
"score": 1,
|
|
807
|
-
"box": {
|
|
808
|
-
"X1": 0,
|
|
809
|
-
"X2": 1,
|
|
810
|
-
"Y1": 0,
|
|
811
|
-
"Y2": 1
|
|
812
|
-
},
|
|
813
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\",\"metadataId\":\"articleType-5\"}, {\"key\":\"section\",\"value\":\"editorial\",\"metadataId\":\"section-5\"}]",
|
|
814
|
-
"groupId": "5",
|
|
753
|
+
"text": "[{\"key\":\"articleType\",\"value\":\"news\"}, {\"key\":\"section\",\"value\":\"editorial\"}]",
|
|
754
|
+
"groupId": "42ba09e0-b2f5-439d-bdae-201e7c37787b",
|
|
815
755
|
"id": "aba453dd-f870-4510-ae40-a19eb52eb7d6"
|
|
816
756
|
}, {
|
|
817
757
|
"label": "metadata",
|
|
@@ -822,21 +762,9 @@ var examplePhotos = [{
|
|
|
822
762
|
"Y1": 0,
|
|
823
763
|
"Y2": 1
|
|
824
764
|
},
|
|
825
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"ads\"
|
|
826
|
-
"groupId": "
|
|
765
|
+
"text": "[{\"key\":\"articleType\",\"value\":\"ads\"}, {\"key\":\"section\",\"value\":\"last page\"}]",
|
|
766
|
+
"groupId": "1",
|
|
827
767
|
"id": "2615bf87-7247-4bde-a0f9-45413034a6a6"
|
|
828
|
-
}, {
|
|
829
|
-
"label": "metadata",
|
|
830
|
-
"score": 1,
|
|
831
|
-
"box": {
|
|
832
|
-
"X1": 0,
|
|
833
|
-
"X2": 1,
|
|
834
|
-
"Y1": 0,
|
|
835
|
-
"Y2": 1
|
|
836
|
-
},
|
|
837
|
-
"text": "[{\"key\":\"articleType\",\"value\":\"news\",\"metadataId\":\"articleType-uuid\"}, {\"key\":\"section\",\"value\":\"editorial\",\"metadataId\":\"section-uuid\"}]",
|
|
838
|
-
"groupId": "42ba09e0-b2f5-439d-bdae-201e7c37787b",
|
|
839
|
-
"id": "metadata-uuid"
|
|
840
768
|
}]
|
|
841
769
|
}]
|
|
842
770
|
},
|
package/Annotator/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
|
3
3
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
4
4
|
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread";
|
|
5
5
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
6
|
-
import React, { useCallback, useEffect, useReducer
|
|
6
|
+
import React, { useCallback, useEffect, useReducer } from "react";
|
|
7
7
|
import makeImmutable, { without } from "seamless-immutable";
|
|
8
8
|
import intersection from "lodash/intersection";
|
|
9
9
|
import MainLayout from "../MainLayout";
|
|
@@ -145,28 +145,6 @@ export var Annotator = function Annotator(_ref) {
|
|
|
145
145
|
var dispatch = useEventCallback(function (action) {
|
|
146
146
|
if (action.type === "HEADER_BUTTON_CLICKED") {
|
|
147
147
|
if (["Exit", "Done", "Save", "Complete"].includes(action.buttonName)) {
|
|
148
|
-
var _state$images$state$s, _state$images$state$s2;
|
|
149
|
-
|
|
150
|
-
// Before exiting, save current image if there are unsaved changes
|
|
151
|
-
if (state.selectedImage !== undefined && ((_state$images$state$s = state.images[state.selectedImage]) === null || _state$images$state$s === void 0 ? void 0 : (_state$images$state$s2 = _state$images$state$s.saveableActions) === null || _state$images$state$s2 === void 0 ? void 0 : _state$images$state$s2.length) > 0) {
|
|
152
|
-
var _currentImage$saveabl;
|
|
153
|
-
|
|
154
|
-
var currentImage = state.images[state.selectedImage];
|
|
155
|
-
var triggerRecalc = intersection(reacalcActionsEnum, currentImage.saveableActions).length > 0;
|
|
156
|
-
var toSaveMetadata = [];
|
|
157
|
-
|
|
158
|
-
if ((_currentImage$saveabl = currentImage.saveableActions) === null || _currentImage$saveabl === void 0 ? void 0 : _currentImage$saveabl.includes("UPDATE_ALBUM_METADATA")) {
|
|
159
|
-
toSaveMetadata = state.albumMetadata;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
dispatchToReducer({
|
|
163
|
-
type: "SAVE_IMAGE",
|
|
164
|
-
image: _objectSpread({}, currentImage),
|
|
165
|
-
triggerRecalc: triggerRecalc,
|
|
166
|
-
toSaveMetadata: toSaveMetadata
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
148
|
return onExit(without(state, "history"));
|
|
171
149
|
} else if (action.buttonName === "Next" && onNextImage) {
|
|
172
150
|
return onNextImage(without(state, "history"));
|
|
@@ -299,77 +277,7 @@ export var Annotator = function Annotator(_ref) {
|
|
|
299
277
|
toSaveMetadata = _state$toSaveImage.toSaveMetadata;
|
|
300
278
|
saveHandler(image, triggerRecalc, toSaveMetadata);
|
|
301
279
|
}
|
|
302
|
-
}, [save, state.toSaveImage]); //
|
|
303
|
-
|
|
304
|
-
var autoSaveTimeoutRef = useRef(null);
|
|
305
|
-
var stateRef = useRef(state); // Keep stateRef in sync with state
|
|
306
|
-
|
|
307
|
-
useEffect(function () {
|
|
308
|
-
stateRef.current = state;
|
|
309
|
-
}, [state]);
|
|
310
|
-
useEffect(function () {
|
|
311
|
-
var _state$lastAction, _state$lastAction2;
|
|
312
|
-
|
|
313
|
-
// Only trigger on UPDATE_METADATA actions for article metadata (with groupId)
|
|
314
|
-
if (((_state$lastAction = state.lastAction) === null || _state$lastAction === void 0 ? void 0 : _state$lastAction.type) === 'UPDATE_METADATA' && ((_state$lastAction2 = state.lastAction) === null || _state$lastAction2 === void 0 ? void 0 : _state$lastAction2.groupId)) {
|
|
315
|
-
var _state$lastAction3 = state.lastAction,
|
|
316
|
-
name = _state$lastAction3.name,
|
|
317
|
-
value = _state$lastAction3.value,
|
|
318
|
-
imageIndex = _state$lastAction3.imageIndex,
|
|
319
|
-
groupId = _state$lastAction3.groupId; // Log the change
|
|
320
|
-
|
|
321
|
-
if (name === 'articleType') {
|
|
322
|
-
console.log("\u23F1\uFE0F [AUTO-SAVE] ArticleType changed to \"".concat(value, "\" for group ").concat(groupId, ". Auto-save will trigger in 1 second..."));
|
|
323
|
-
} else {
|
|
324
|
-
console.log("\u23F1\uFE0F [AUTO-SAVE] ".concat(name, " changed to \"").concat(value, "\" for group ").concat(groupId, ". Auto-save will trigger in 1 second..."));
|
|
325
|
-
} // Clear any existing timeout
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (autoSaveTimeoutRef.current) {
|
|
329
|
-
clearTimeout(autoSaveTimeoutRef.current);
|
|
330
|
-
console.log("\u23F1\uFE0F [AUTO-SAVE] Previous auto-save cancelled, restarting timer...");
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (imageIndex !== undefined) {
|
|
334
|
-
// Debounce: wait 1 second after last change before saving
|
|
335
|
-
autoSaveTimeoutRef.current = setTimeout(function () {
|
|
336
|
-
var _latestState$images, _imageToSave$saveable;
|
|
337
|
-
|
|
338
|
-
// Read latest state from ref
|
|
339
|
-
var latestState = stateRef.current;
|
|
340
|
-
var imageToSave = latestState === null || latestState === void 0 ? void 0 : (_latestState$images = latestState.images) === null || _latestState$images === void 0 ? void 0 : _latestState$images[imageIndex]; // Double-check that there are still unsaved changes and image exists
|
|
341
|
-
|
|
342
|
-
if (imageToSave === null || imageToSave === void 0 ? void 0 : (_imageToSave$saveable = imageToSave.saveableActions) === null || _imageToSave$saveable === void 0 ? void 0 : _imageToSave$saveable.includes("UPDATE_METADATA")) {
|
|
343
|
-
var _imageToSave$saveable2;
|
|
344
|
-
|
|
345
|
-
console.log("\uD83D\uDCBE [AUTO-SAVE] Triggering auto-save for image ".concat(imageToSave.id, " (group ").concat(groupId, ")..."));
|
|
346
|
-
var triggerRecalc = intersection(reacalcActionsEnum, imageToSave.saveableActions).length > 0;
|
|
347
|
-
var toSaveMetadata = [];
|
|
348
|
-
|
|
349
|
-
if ((_imageToSave$saveable2 = imageToSave.saveableActions) === null || _imageToSave$saveable2 === void 0 ? void 0 : _imageToSave$saveable2.includes("UPDATE_ALBUM_METADATA")) {
|
|
350
|
-
toSaveMetadata = latestState.albumMetadata || [];
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
dispatchToReducer({
|
|
354
|
-
type: "SAVE_IMAGE",
|
|
355
|
-
image: _objectSpread({}, imageToSave),
|
|
356
|
-
triggerRecalc: triggerRecalc,
|
|
357
|
-
toSaveMetadata: toSaveMetadata
|
|
358
|
-
});
|
|
359
|
-
} else {
|
|
360
|
-
console.log("\u26A0\uFE0F [AUTO-SAVE] Skipping auto-save - no unsaved changes for image ".concat(imageIndex));
|
|
361
|
-
}
|
|
362
|
-
}, 1000); // 1 second delay
|
|
363
|
-
}
|
|
364
|
-
} // Cleanup timeout on unmount or when dependencies change
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
return function () {
|
|
368
|
-
if (autoSaveTimeoutRef.current) {
|
|
369
|
-
clearTimeout(autoSaveTimeoutRef.current);
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
}, [state.lastAction, dispatchToReducer]); // polling of images
|
|
280
|
+
}, [save, state.toSaveImage]); // polling of images
|
|
373
281
|
|
|
374
282
|
useEffect(function () {
|
|
375
283
|
if (state.toPollImages.length > 0) {
|
|
@@ -1240,7 +1240,7 @@ export default (function (state, action) {
|
|
|
1240
1240
|
value: value
|
|
1241
1241
|
});
|
|
1242
1242
|
} else {
|
|
1243
|
-
var _state$images$
|
|
1243
|
+
var _state$images$_imageI3, _state$images$_imageI4;
|
|
1244
1244
|
|
|
1245
1245
|
// update metadata of article
|
|
1246
1246
|
if (_groupId2) {
|
|
@@ -1266,42 +1266,24 @@ export default (function (state, action) {
|
|
|
1266
1266
|
return state;
|
|
1267
1267
|
}
|
|
1268
1268
|
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
// This ensures the saveableAction is added to the image being modified, not the currently selected one
|
|
1272
|
-
|
|
1273
|
-
if (state.images[_imageIndex]) {
|
|
1274
|
-
var _state$images$_imageI3;
|
|
1275
|
-
|
|
1276
|
-
var currentSaveableActions = ((_state$images$_imageI3 = state.images[_imageIndex]) === null || _state$images$_imageI3 === void 0 ? void 0 : _state$images$_imageI3.saveableActions) || [];
|
|
1277
|
-
state = setIn(state, ["images", _imageIndex, "saveableActions"], [].concat(_toConsumableArray(currentSaveableActions), ["UPDATE_METADATA"]));
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1269
|
+
articleMetadata[toBeUpdatedMetadataIdx].value = value;
|
|
1270
|
+
state = addSaveableAction(state, "UPDATE_METADATA");
|
|
1280
1271
|
return setIn(state, ["images", _imageIndex, "regions", articleMetadataRegionIdx], _objectSpread({}, articleRegionToUpdate, {
|
|
1281
1272
|
text: JSON.stringify(articleMetadata)
|
|
1282
1273
|
}));
|
|
1283
1274
|
} // update metadata of image
|
|
1284
1275
|
|
|
1285
1276
|
|
|
1286
|
-
var _metadataIndex = (_state$images$
|
|
1277
|
+
var _metadataIndex = (_state$images$_imageI3 = state.images[_imageIndex]) === null || _state$images$_imageI3 === void 0 ? void 0 : (_state$images$_imageI4 = _state$images$_imageI3.metadata) === null || _state$images$_imageI4 === void 0 ? void 0 : _state$images$_imageI4.findIndex(function (mt) {
|
|
1287
1278
|
return mt.key === name;
|
|
1288
1279
|
});
|
|
1289
1280
|
|
|
1290
1281
|
if (_metadataIndex < 0) {
|
|
1291
1282
|
console.error("can't find photo metadata by key \"".concat(name, "\""));
|
|
1292
1283
|
return state;
|
|
1293
|
-
} // Add saveableAction to the correct image (using imageIndex from action, not selectedImage)
|
|
1294
|
-
// This ensures the saveableAction is added to the image being modified, not the currently selected one
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
if (state.images[_imageIndex]) {
|
|
1298
|
-
var _state$images$_imageI6;
|
|
1299
|
-
|
|
1300
|
-
var _currentSaveableActions = ((_state$images$_imageI6 = state.images[_imageIndex]) === null || _state$images$_imageI6 === void 0 ? void 0 : _state$images$_imageI6.saveableActions) || [];
|
|
1301
|
-
|
|
1302
|
-
state = setIn(state, ["images", _imageIndex, "saveableActions"], [].concat(_toConsumableArray(_currentSaveableActions), ["UPDATE_METADATA"]));
|
|
1303
1284
|
}
|
|
1304
1285
|
|
|
1286
|
+
state = addSaveableAction(state, "UPDATE_METADATA");
|
|
1305
1287
|
return setIn(state, ["images", _imageIndex, "metadata", _metadataIndex], {
|
|
1306
1288
|
key: name,
|
|
1307
1289
|
value: value
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.editor-toggle-wrapper {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: flex-start;
|
|
5
|
+
gap: 0.5rem; /* space between Spellcheck and Edit mode rows */
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/* Smaller toggle size only for Editor switches */
|
|
9
|
+
.editor-switch.switch {
|
|
10
|
+
width: 44px;
|
|
11
|
+
height: 24px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.editor-switch .slider {
|
|
15
|
+
border-radius: 24px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.editor-switch .slider:before {
|
|
19
|
+
height: 18px;
|
|
20
|
+
width: 18px;
|
|
21
|
+
left: 3px;
|
|
22
|
+
bottom: 3px;
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.editor-switch input:checked + .slider:before {
|
|
27
|
+
transform: translateX(18px);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@searpent/react-image-annotate",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"@editorjs/editorjs": "^2.25.0",
|
|
6
6
|
"@editorjs/paragraph": "^2.8.0",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"storybook": "start-storybook -p 9090 -s public",
|
|
61
61
|
"build": "npm run build:babel && cp ./package.json ./dist/package.json && cp ./README.md ./dist/README.md",
|
|
62
62
|
"dist": "npm run build && cd dist && npm publish",
|
|
63
|
-
"build:babel": "NODE_ENV=production babel ./src --ignore \"src/**/*.story.js\" --out-dir=./dist && rm dist/index.js && cp dist/lib.js dist/index.js && cp src/PageSelector/page-selector.css dist/PageSelector/ && cp src/Locker/locker.css dist/Locker/ && cp src/Errorer/errorer.css dist/Errorer/ && cp src/Editor/annotation-plugin/annotation.css dist/Editor/annotation-plugin",
|
|
63
|
+
"build:babel": "NODE_ENV=production babel ./src --ignore \"src/**/*.story.js\" --out-dir=./dist && rm dist/index.js && cp dist/lib.js dist/index.js && cp src/PageSelector/page-selector.css dist/PageSelector/ && cp src/Locker/locker.css dist/Locker/ && cp src/Errorer/errorer.css dist/Errorer/ && cp src/Editor/editor.css dist/Editor/ && cp src/Editor/annotation-plugin/annotation.css dist/Editor/annotation-plugin",
|
|
64
64
|
"build-storybook": "build-storybook",
|
|
65
65
|
"build:gh-pages": "CI=false react-scripts build && mkdir build/demo && cp build/index.html build/demo/index.html",
|
|
66
66
|
"gh-pages": "npm run build:gh-pages && gh-pages -d build",
|