@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.
@@ -750,68 +750,8 @@ var examplePhotos = [{
750
750
  "Y1": 0,
751
751
  "Y2": 1
752
752
  },
753
- "text": "[{\"key\":\"articleType\",\"value\":\"news\",\"metadataId\":\"articleType-0\"}, {\"key\":\"section\",\"value\":\"editorial\",\"metadataId\":\"section-0\"}]",
754
- "groupId": "0",
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\",\"metadataId\":\"articleType-6\"}, {\"key\":\"section\",\"value\":\"last page\",\"metadataId\":\"section-6\"}]",
826
- "groupId": "6",
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
  },
@@ -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, useRef } from "react";
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]); // Auto-save article metadata changes after a delay (debounced)
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$_imageI4, _state$images$_imageI5;
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
- var oldValue = articleMetadata[toBeUpdatedMetadataIdx].value;
1270
- articleMetadata[toBeUpdatedMetadataIdx].value = value; // Add saveableAction to the correct image (using imageIndex from action, not selectedImage)
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$_imageI4 = state.images[_imageIndex]) === null || _state$images$_imageI4 === void 0 ? void 0 : (_state$images$_imageI5 = _state$images$_imageI4.metadata) === null || _state$images$_imageI5 === void 0 ? void 0 : _state$images$_imageI5.findIndex(function (mt) {
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.0",
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",