@searpent/react-image-annotate 2.0.9 → 2.0.12

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.
@@ -776,6 +776,12 @@ var examplePhotos = [{
776
776
  "metadata": [{
777
777
  "key": "page",
778
778
  "value": "1"
779
+ }, {
780
+ "key": "section",
781
+ "value": "lokální zpravodajství"
782
+ }, {
783
+ "key": "mutation",
784
+ "value": "hřensko"
779
785
  }]
780
786
  }, {
781
787
  "id": "431fc636-d6d1-4e20-a35b-cc7a201c1833",
@@ -13,68 +13,82 @@ import historyHandler from "./reducers/history-handler.js";
13
13
  import imageReducer from "./reducers/image-reducer.js";
14
14
  import useEventCallback from "use-event-callback";
15
15
  import videoReducer from "./reducers/video-reducer.js";
16
- export var Annotator = function Annotator(_ref) {
17
- var images = _ref.images,
18
- allowedArea = _ref.allowedArea,
19
- _ref$selectedImage = _ref.selectedImage,
20
- selectedImage = _ref$selectedImage === void 0 ? images && images.length > 0 ? 0 : undefined : _ref$selectedImage,
21
- showPointDistances = _ref.showPointDistances,
22
- pointDistancePrecision = _ref.pointDistancePrecision,
23
- _ref$showTags = _ref.showTags,
24
- showTags = _ref$showTags === void 0 ? getFromLocalStorage("showTags", true) : _ref$showTags,
25
- _ref$enabledTools = _ref.enabledTools,
26
- enabledTools = _ref$enabledTools === void 0 ? ["select", "create-point", "create-box", "create-polygon", "create-line", "create-expanding-line", "show-mask"] : _ref$enabledTools,
27
- _ref$selectedTool = _ref.selectedTool,
28
- selectedTool = _ref$selectedTool === void 0 ? "select" : _ref$selectedTool,
29
- _ref$regionTagList = _ref.regionTagList,
30
- regionTagList = _ref$regionTagList === void 0 ? [] : _ref$regionTagList,
31
- _ref$regionClsList = _ref.regionClsList,
32
- regionClsList = _ref$regionClsList === void 0 ? [] : _ref$regionClsList,
33
- _ref$imageTagList = _ref.imageTagList,
34
- imageTagList = _ref$imageTagList === void 0 ? [] : _ref$imageTagList,
35
- _ref$imageClsList = _ref.imageClsList,
36
- imageClsList = _ref$imageClsList === void 0 ? [] : _ref$imageClsList,
37
- _ref$keyframes = _ref.keyframes,
38
- keyframes = _ref$keyframes === void 0 ? {} : _ref$keyframes,
39
- _ref$taskDescription = _ref.taskDescription,
40
- taskDescription = _ref$taskDescription === void 0 ? "" : _ref$taskDescription,
41
- _ref$fullImageSegment = _ref.fullImageSegmentationMode,
42
- fullImageSegmentationMode = _ref$fullImageSegment === void 0 ? false : _ref$fullImageSegment,
43
- RegionEditLabel = _ref.RegionEditLabel,
44
- videoSrc = _ref.videoSrc,
45
- _ref$videoTime = _ref.videoTime,
46
- videoTime = _ref$videoTime === void 0 ? 0 : _ref$videoTime,
47
- videoName = _ref.videoName,
48
- onExit = _ref.onExit,
49
- onNextImage = _ref.onNextImage,
50
- onPrevImage = _ref.onPrevImage,
51
- keypointDefinitions = _ref.keypointDefinitions,
52
- _ref$autoSegmentation = _ref.autoSegmentationOptions,
53
- autoSegmentationOptions = _ref$autoSegmentation === void 0 ? {
16
+
17
+ function extractAllowedGroups(images) {
18
+ var allowedGroups = [];
19
+ images.forEach(function (image) {
20
+ return image.regions.forEach(function (_ref) {
21
+ var groupId = _ref.groupId;
22
+
23
+ if (!allowedGroups.includes(groupId)) {
24
+ allowedGroups.push(groupId);
25
+ }
26
+ });
27
+ });
28
+ return allowedGroups;
29
+ }
30
+
31
+ export var Annotator = function Annotator(_ref2) {
32
+ var images = _ref2.images,
33
+ allowedArea = _ref2.allowedArea,
34
+ _ref2$selectedImage = _ref2.selectedImage,
35
+ selectedImage = _ref2$selectedImage === void 0 ? images && images.length > 0 ? 0 : undefined : _ref2$selectedImage,
36
+ showPointDistances = _ref2.showPointDistances,
37
+ pointDistancePrecision = _ref2.pointDistancePrecision,
38
+ _ref2$showTags = _ref2.showTags,
39
+ showTags = _ref2$showTags === void 0 ? getFromLocalStorage("showTags", true) : _ref2$showTags,
40
+ _ref2$enabledTools = _ref2.enabledTools,
41
+ enabledTools = _ref2$enabledTools === void 0 ? ["select", "create-point", "create-box", "create-polygon", "create-line", "create-expanding-line", "show-mask"] : _ref2$enabledTools,
42
+ _ref2$selectedTool = _ref2.selectedTool,
43
+ selectedTool = _ref2$selectedTool === void 0 ? "select" : _ref2$selectedTool,
44
+ _ref2$regionTagList = _ref2.regionTagList,
45
+ regionTagList = _ref2$regionTagList === void 0 ? [] : _ref2$regionTagList,
46
+ _ref2$regionClsList = _ref2.regionClsList,
47
+ regionClsList = _ref2$regionClsList === void 0 ? [] : _ref2$regionClsList,
48
+ _ref2$imageTagList = _ref2.imageTagList,
49
+ imageTagList = _ref2$imageTagList === void 0 ? [] : _ref2$imageTagList,
50
+ _ref2$imageClsList = _ref2.imageClsList,
51
+ imageClsList = _ref2$imageClsList === void 0 ? [] : _ref2$imageClsList,
52
+ _ref2$keyframes = _ref2.keyframes,
53
+ keyframes = _ref2$keyframes === void 0 ? {} : _ref2$keyframes,
54
+ _ref2$taskDescription = _ref2.taskDescription,
55
+ taskDescription = _ref2$taskDescription === void 0 ? "" : _ref2$taskDescription,
56
+ _ref2$fullImageSegmen = _ref2.fullImageSegmentationMode,
57
+ fullImageSegmentationMode = _ref2$fullImageSegmen === void 0 ? false : _ref2$fullImageSegmen,
58
+ RegionEditLabel = _ref2.RegionEditLabel,
59
+ videoSrc = _ref2.videoSrc,
60
+ _ref2$videoTime = _ref2.videoTime,
61
+ videoTime = _ref2$videoTime === void 0 ? 0 : _ref2$videoTime,
62
+ videoName = _ref2.videoName,
63
+ onExit = _ref2.onExit,
64
+ onNextImage = _ref2.onNextImage,
65
+ onPrevImage = _ref2.onPrevImage,
66
+ keypointDefinitions = _ref2.keypointDefinitions,
67
+ _ref2$autoSegmentatio = _ref2.autoSegmentationOptions,
68
+ autoSegmentationOptions = _ref2$autoSegmentatio === void 0 ? {
54
69
  type: "autoseg"
55
- } : _ref$autoSegmentation,
56
- hideHeader = _ref.hideHeader,
57
- hideHeaderText = _ref.hideHeaderText,
58
- hideNext = _ref.hideNext,
59
- hidePrev = _ref.hidePrev,
60
- hideClone = _ref.hideClone,
61
- hideSettings = _ref.hideSettings,
62
- hideFullScreen = _ref.hideFullScreen,
63
- hideSave = _ref.hideSave,
64
- allowComments = _ref.allowComments,
65
- onImagesChange = _ref.onImagesChange,
66
- groups = _ref.groups,
67
- onGroupSelect = _ref.onGroupSelect,
68
- hideHistory = _ref.hideHistory,
69
- hideNotEditingLabel = _ref.hideNotEditingLabel,
70
- showEditor = _ref.showEditor,
71
- showPageSelector = _ref.showPageSelector,
72
- clsColors = _ref.clsColors,
73
- groupColors = _ref.groupColors,
74
- onRecalc = _ref.onRecalc,
75
- onSave = _ref.onSave,
76
- allowedGroups = _ref.allowedGroups,
77
- metadata = _ref.metadata;
70
+ } : _ref2$autoSegmentatio,
71
+ hideHeader = _ref2.hideHeader,
72
+ hideHeaderText = _ref2.hideHeaderText,
73
+ hideNext = _ref2.hideNext,
74
+ hidePrev = _ref2.hidePrev,
75
+ hideClone = _ref2.hideClone,
76
+ hideSettings = _ref2.hideSettings,
77
+ hideFullScreen = _ref2.hideFullScreen,
78
+ hideSave = _ref2.hideSave,
79
+ allowComments = _ref2.allowComments,
80
+ onImagesChange = _ref2.onImagesChange,
81
+ groups = _ref2.groups,
82
+ onGroupSelect = _ref2.onGroupSelect,
83
+ hideHistory = _ref2.hideHistory,
84
+ hideNotEditingLabel = _ref2.hideNotEditingLabel,
85
+ showEditor = _ref2.showEditor,
86
+ showPageSelector = _ref2.showPageSelector,
87
+ clsColors = _ref2.clsColors,
88
+ groupColors = _ref2.groupColors,
89
+ onRecalc = _ref2.onRecalc,
90
+ onSave = _ref2.onSave,
91
+ metadata = _ref2.metadata;
78
92
 
79
93
  if (typeof selectedImage === "string") {
80
94
  selectedImage = (images || []).findIndex(function (img) {
@@ -83,6 +97,7 @@ export var Annotator = function Annotator(_ref) {
83
97
  if (selectedImage === -1) selectedImage = undefined;
84
98
  }
85
99
 
100
+ var allowedGroups = extractAllowedGroups(images);
86
101
  var annotationType = images ? "image" : "video";
87
102
 
88
103
  var _useReducer = useReducer(historyHandler(combineReducers(annotationType === "image" ? imageReducer : videoReducer, generalReducer)), makeImmutable(_objectSpread({
@@ -118,7 +133,8 @@ export var Annotator = function Annotator(_ref) {
118
133
  }, {
119
134
  imagesUpdatedAt: null,
120
135
  imagesSavedAt: null,
121
- metadata: metadata
136
+ metadata: metadata,
137
+ allowedGroups: allowedGroups || []
122
138
  }))),
123
139
  _useReducer2 = _slicedToArray(_useReducer, 2),
124
140
  state = _useReducer2[0],
@@ -147,7 +163,7 @@ export var Annotator = function Annotator(_ref) {
147
163
  var handleSaveClick =
148
164
  /*#__PURE__*/
149
165
  function () {
150
- var _ref2 = _asyncToGenerator(
166
+ var _ref3 = _asyncToGenerator(
151
167
  /*#__PURE__*/
152
168
  _regeneratorRuntime.mark(function _callee(e) {
153
169
  return _regeneratorRuntime.wrap(function _callee$(_context) {
@@ -179,7 +195,7 @@ export var Annotator = function Annotator(_ref) {
179
195
  }));
180
196
 
181
197
  return function handleSaveClick(_x) {
182
- return _ref2.apply(this, arguments);
198
+ return _ref3.apply(this, arguments);
183
199
  };
184
200
  }();
185
201
 
@@ -191,16 +207,23 @@ export var Annotator = function Annotator(_ref) {
191
207
  }
192
208
  };
193
209
 
194
- var handleMetadataChange = function handleMetadataChange(_ref3) {
195
- var name = _ref3.name,
196
- value = _ref3.value,
197
- imageIndex = _ref3.imageIndex;
210
+ var handleMetadataChange = function handleMetadataChange(_ref4) {
211
+ var name = _ref4.name,
212
+ value = _ref4.value,
213
+ imageIndex = _ref4.imageIndex;
198
214
  dispatchToReducer({
199
215
  type: "UPDATE_METADATA",
200
216
  name: name,
201
217
  value: value,
202
218
  imageIndex: imageIndex
203
219
  });
220
+ };
221
+
222
+ var handleAddGroup = function handleAddGroup(group) {
223
+ dispatchToReducer({
224
+ type: "ADD_GROUP",
225
+ group: group
226
+ });
204
227
  }; // trigger this on every BBox manipulation (there is currently no way to detect adding of new box!)
205
228
 
206
229
 
@@ -228,10 +251,10 @@ export var Annotator = function Annotator(_ref) {
228
251
  }, [onImagesChange, selectedImage]);
229
252
  if (!images && !videoSrc) return 'Missing required prop "images" or "videoSrc"';
230
253
 
231
- var _ref4 = state.imagesSavedAt < state.imagesUpdatedAt ? [true, true] : [false, false],
232
- _ref5 = _slicedToArray(_ref4, 2),
233
- recalcActive = _ref5[0],
234
- saveActive = _ref5[1];
254
+ var _ref5 = state.imagesSavedAt < state.imagesUpdatedAt ? [true, true] : [false, false],
255
+ _ref6 = _slicedToArray(_ref5, 2),
256
+ recalcActive = _ref6[0],
257
+ saveActive = _ref6[1];
235
258
 
236
259
  return React.createElement(SettingsProvider, {
237
260
  clsColors: clsColors,
@@ -261,8 +284,8 @@ export var Annotator = function Annotator(_ref) {
261
284
  onSave: handleSaveClick,
262
285
  saveActive: recalcActive,
263
286
  recalcActive: saveActive,
264
- allowedGroups: allowedGroups,
265
- onMetadataChange: handleMetadataChange
287
+ onMetadataChange: handleMetadataChange,
288
+ onAddGroup: handleAddGroup
266
289
  }));
267
290
  };
268
291
  export default Annotator;
@@ -926,6 +926,15 @@ export default (function (state, action) {
926
926
  }));
927
927
  }
928
928
 
929
+ case "DELETE_GROUP":
930
+ {
931
+ var groupId = action.groupId;
932
+ if (groupId === null || groupId === undefined) return state;
933
+ return setIn(state, [].concat(_toConsumableArray(pathToActiveImage), ["regions"]), (activeImage.regions || []).filter(function (r) {
934
+ return r.groupId !== groupId;
935
+ }));
936
+ }
937
+
929
938
  case "DELETE_SELECTED_REGION":
930
939
  {
931
940
  return setIn(state, [].concat(_toConsumableArray(pathToActiveImage), ["regions"]), (activeImage.regions || []).filter(function (r) {
@@ -1144,6 +1153,13 @@ export default (function (state, action) {
1144
1153
  }
1145
1154
  }
1146
1155
 
1156
+ case "ADD_GROUP":
1157
+ {
1158
+ var group = action.group;
1159
+ var newAllowedGroups = [].concat(_toConsumableArray(state.allowedGroups), [group]);
1160
+ return setIn(state, ["allowedGroups"], newAllowedGroups);
1161
+ }
1162
+
1147
1163
  default:
1148
1164
  break;
1149
1165
  }
@@ -0,0 +1,137 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import React, { memo, useState } from "react";
3
+ import SidebarBoxContainer from "../SidebarBoxContainer";
4
+ import FilterNoneIcon from '@mui/icons-material/FilterNone';
5
+ import { styled } from "@mui/material/styles";
6
+ import { createTheme, ThemeProvider } from "@mui/material/styles";
7
+ import { grey } from "@mui/material/colors";
8
+ var theme = createTheme();
9
+ var GroupItemDiv = styled("div")(function (_ref) {
10
+ var theme = _ref.theme;
11
+ return {
12
+ display: "flex",
13
+ flexDirection: "column",
14
+ marginBottom: "1rem",
15
+ "& > label": {
16
+ fontSize: "1rem",
17
+ marginBottom: ".5rem",
18
+ textTransform: "capitalize"
19
+ }
20
+ };
21
+ });
22
+
23
+ var GroupItem = function GroupItem(_ref2) {
24
+ var group = _ref2.group;
25
+ return React.createElement(GroupItemDiv, null, group);
26
+ };
27
+
28
+ var GroupList = function GroupList(_ref3) {
29
+ var groups = _ref3.groups;
30
+ return React.createElement("div", null, React.createElement("h2", null, "Groups"), groups.map(function (g) {
31
+ return React.createElement(GroupItem, {
32
+ key: g,
33
+ group: g
34
+ });
35
+ }));
36
+ };
37
+
38
+ var AddGroupFormDiv = styled("div")(function (_ref4) {
39
+ var theme = _ref4.theme;
40
+ return {
41
+ display: "flex",
42
+ flexDirection: "row"
43
+ };
44
+ });
45
+
46
+ var AddGroupFrom = function AddGroupFrom(_ref5) {
47
+ var onAddGroup = _ref5.onAddGroup;
48
+
49
+ var _useState = useState(""),
50
+ _useState2 = _slicedToArray(_useState, 2),
51
+ value = _useState2[0],
52
+ setValue = _useState2[1];
53
+
54
+ var handleChange = function handleChange(e) {
55
+ setValue(e.target.value);
56
+ };
57
+
58
+ var handleSubmit = function handleSubmit(e) {
59
+ e.preventDefault();
60
+ onAddGroup(value);
61
+ setValue('');
62
+ };
63
+
64
+ return React.createElement(AddGroupFormDiv, null, React.createElement("form", {
65
+ onSubmit: handleSubmit,
66
+ style: {
67
+ display: "flex",
68
+ paddingRight: "6px"
69
+ }
70
+ }, React.createElement("input", {
71
+ type: "text",
72
+ value: value,
73
+ name: "new-group",
74
+ placeholder: "New group name",
75
+ onChange: handleChange,
76
+ style: {
77
+ marginRight: "1rem"
78
+ }
79
+ }), React.createElement("input", {
80
+ type: "submit",
81
+ value: "Create group"
82
+ })));
83
+ };
84
+
85
+ var DivContainer = styled("div")(function (_ref6) {
86
+ var theme = _ref6.theme;
87
+ return {
88
+ paddingLeft: 16,
89
+ paddingRight: 16,
90
+ fontSize: 12,
91
+ "& h1": {
92
+ fontSize: 18
93
+ },
94
+ "& h2": {
95
+ fontSize: 14
96
+ },
97
+ "& h3": {
98
+ fontSize: 12
99
+ },
100
+ "& h4": {
101
+ fontSize: 12
102
+ },
103
+ "& h5": {
104
+ fontSize: 12
105
+ },
106
+ "& h6": {
107
+ fontSize: 12
108
+ },
109
+ "& p": {
110
+ fontSize: 12
111
+ },
112
+ "& a": {},
113
+ "& img": {
114
+ width: "100%"
115
+ }
116
+ };
117
+ });
118
+ export var GroupsEditorSidebarBox = function GroupsEditorSidebarBox(_ref7) {
119
+ var groups = _ref7.groups,
120
+ onAddGroup = _ref7.onAddGroup;
121
+ return React.createElement(ThemeProvider, {
122
+ theme: theme
123
+ }, React.createElement(SidebarBoxContainer, {
124
+ title: "Groups",
125
+ icon: React.createElement(FilterNoneIcon, {
126
+ style: {
127
+ color: grey[700]
128
+ }
129
+ }),
130
+ expandedByDefault: true
131
+ }, React.createElement(DivContainer, null, React.createElement("h2", null, "Add new group"), React.createElement(AddGroupFrom, {
132
+ onAddGroup: onAddGroup
133
+ }), React.createElement(GroupList, {
134
+ groups: groups
135
+ }))));
136
+ };
137
+ export default memo(GroupsEditorSidebarBox);
@@ -96,6 +96,7 @@ export var ImageCanvas = function ImageCanvas(_ref2) {
96
96
  onSelectRegion = _ref2.onSelectRegion,
97
97
  onBeginMovePoint = _ref2.onBeginMovePoint,
98
98
  onDeleteRegion = _ref2.onDeleteRegion,
99
+ onDeleteGroup = _ref2.onDeleteGroup,
99
100
  onChangeVideoTime = _ref2.onChangeVideoTime,
100
101
  onChangeVideoPlaying = _ref2.onChangeVideoPlaying,
101
102
  onRegionClassAdded = _ref2.onRegionClassAdded,
@@ -349,6 +350,7 @@ export var ImageCanvas = function ImageCanvas(_ref2) {
349
350
  onChangeRegion: onChangeRegion,
350
351
  onCloseRegionEdit: onCloseRegionEdit,
351
352
  onDeleteRegion: onDeleteRegion,
353
+ onDeleteGroup: onDeleteGroup,
352
354
  layoutParams: layoutParams,
353
355
  imageSrc: imageSrc,
354
356
  RegionEditLabel: RegionEditLabel,
@@ -365,6 +367,7 @@ export var ImageCanvas = function ImageCanvas(_ref2) {
365
367
  allowedTags: regionTagList,
366
368
  onChange: onChangeRegion,
367
369
  onDelete: onDeleteRegion,
370
+ onDeleteGroup: onDeleteGroup,
368
371
  editing: true,
369
372
  region: highlightedRegion,
370
373
  imageSrc: imageSrc,
@@ -18,6 +18,7 @@ import SettingsDialog from "../SettingsDialog";
18
18
  import TagsSidebarBox from "../TagsSidebarBox";
19
19
  import TaskDescription from "../TaskDescriptionSidebarBox";
20
20
  import MetadataEditor from "../MetadataEditorSidebarBox";
21
+ import GroupsEditor from "../GroupsEditorSidebarBox";
21
22
  import Workspace from "react-material-workspace-layout/Workspace";
22
23
  import classnames from "classnames";
23
24
  import getActiveImage from "../Annotator/reducers/get-active-image";
@@ -32,7 +33,7 @@ import { useSettings } from "../SettingsProvider";
32
33
  import { withHotKeys } from "react-hotkeys";
33
34
  import Editor from "../Editor";
34
35
  import regionsToBlocks from '../utils/regions-to-blocks';
35
- import PagesSelector from "../PageSelector"; // import Fullscreen from "../Fullscreen"
36
+ import PageSelector from "../PageSelector"; // import Fullscreen from "../Fullscreen"
36
37
 
37
38
  var emptyArr = [];
38
39
  var theme = createTheme();
@@ -113,9 +114,8 @@ export var MainLayout = function MainLayout(_ref4) {
113
114
  recalcActive = _ref4$recalcActive === void 0 ? false : _ref4$recalcActive,
114
115
  _ref4$saveActive = _ref4.saveActive,
115
116
  saveActive = _ref4$saveActive === void 0 ? false : _ref4$saveActive,
116
- _ref4$allowedGroups = _ref4.allowedGroups,
117
- allowedGroups = _ref4$allowedGroups === void 0 ? {} : _ref4$allowedGroups,
118
- onMetadataChange = _ref4.onMetadataChange;
117
+ onMetadataChange = _ref4.onMetadataChange,
118
+ onAddGroup = _ref4.onAddGroup;
119
119
  var classes = useStyles();
120
120
  var settings = useSettings();
121
121
  var fullScreenHandle = useFullScreenHandle();
@@ -209,6 +209,7 @@ export var MainLayout = function MainLayout(_ref4) {
209
209
  onBeginRegionEdit: action("OPEN_REGION_EDITOR", "region"),
210
210
  onCloseRegionEdit: action("CLOSE_REGION_EDITOR", "region"),
211
211
  onDeleteRegion: action("DELETE_REGION", "region"),
212
+ onDeleteGroup: action("DELETE_GROUP", "groupId"),
212
213
  onBeginBoxTransform: action("BEGIN_BOX_TRANSFORM", "box", "directions"),
213
214
  onBeginMovePolygonPoint: action("BEGIN_MOVE_POLYGON_POINT", "polygon", "pointIndex"),
214
215
  onBeginMoveKeypoint: action("BEGIN_MOVE_KEYPOINT", "region", "keypointId"),
@@ -223,7 +224,7 @@ export var MainLayout = function MainLayout(_ref4) {
223
224
  onRegionClassAdded: onRegionClassAdded,
224
225
  allowComments: state.allowComments,
225
226
  hideNotEditingLabel: hideNotEditingLabel,
226
- allowedGroups: allowedGroups
227
+ allowedGroups: state.allowedGroups
227
228
  }));
228
229
  var onClickIconSidebarItem = useEventCallback(function (item) {
229
230
  dispatch({
@@ -280,7 +281,8 @@ export var MainLayout = function MainLayout(_ref4) {
280
281
  isActive: idx === state.selectedImage,
281
282
  pageNumber: (i === null || i === void 0 ? void 0 : (_i$metadata = i.metadata) === null || _i$metadata === void 0 ? void 0 : _i$metadata.find(function (md) {
282
283
  return md.key === "page";
283
- }).value) || null
284
+ }).value) || null,
285
+ metadata: i.metadata || []
284
286
  };
285
287
  });
286
288
 
@@ -314,13 +316,14 @@ export var MainLayout = function MainLayout(_ref4) {
314
316
  display: 'flex',
315
317
  flexDirection: 'row'
316
318
  }
317
- }, showPageSelector && React.createElement(PagesSelector, {
319
+ }, showPageSelector && React.createElement(PageSelector, {
318
320
  pages: pages,
319
321
  onPageClick: handlePageClick,
320
322
  onRecalc: onRecalc,
321
323
  onSave: onSave,
322
324
  saveActive: saveActive,
323
- recalcActive: recalcActive
325
+ recalcActive: recalcActive,
326
+ onMetadataChange: onMetadataChange
324
327
  }), React.createElement(Workspace, {
325
328
  allowFullscreen: true,
326
329
  iconDictionary: iconDictionary,
@@ -356,7 +359,7 @@ export var MainLayout = function MainLayout(_ref4) {
356
359
  onClickHeaderItem: onClickHeaderItem,
357
360
  onClickIconSidebarItem: onClickIconSidebarItem,
358
361
  selectedTools: [state.selectedTool, state.showTags && "show-tags", state.showMask && "show-mask"].filter(Boolean),
359
- iconSidebarItems: [{
362
+ iconSidebarItems: !state.enabledTools ? [] : [{
360
363
  name: "select",
361
364
  helperText: "Select" + getHotkeyHelpText("select_tool"),
362
365
  alwaysShowing: true
@@ -447,6 +450,9 @@ export var MainLayout = function MainLayout(_ref4) {
447
450
  }), React.createElement(MetadataEditor, {
448
451
  state: state,
449
452
  onMetadataChange: onMetadataChange
453
+ }), React.createElement(GroupsEditor, {
454
+ groups: state.allowedGroups,
455
+ onAddGroup: onAddGroup
450
456
  })].filter(Boolean)
451
457
  }, canvas), showEditor && React.createElement(EditorWrapper, {
452
458
  id: "editor-wrapper"
@@ -1,4 +1,5 @@
1
- import React from 'react';
1
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import React, { useState } from 'react';
2
3
  import classnames from "classnames";
3
4
 
4
5
  require('./page-selector.css').toString();
@@ -25,17 +26,26 @@ function PageThumbnail(_ref) {
25
26
  }, pageNumber)));
26
27
  }
27
28
 
28
- function PagesSelector(_ref2) {
29
+ function PageSelector(_ref2) {
29
30
  var pages = _ref2.pages,
30
31
  onPageClick = _ref2.onPageClick,
31
32
  onRecalc = _ref2.onRecalc,
32
33
  onSave = _ref2.onSave,
33
34
  recalcActive = _ref2.recalcActive,
34
- saveActive = _ref2.saveActive;
35
+ saveActive = _ref2.saveActive,
36
+ onMetadataChange = _ref2.onMetadataChange;
37
+
38
+ var _useState = useState(false),
39
+ _useState2 = _slicedToArray(_useState, 2),
40
+ showMetadata = _useState2[0],
41
+ setShowMetadata = _useState2[1];
42
+
35
43
  return React.createElement("div", {
36
- className: "page-selector"
44
+ className: classnames('page-selector', {
45
+ 'page-selector--opened': showMetadata
46
+ })
37
47
  }, React.createElement("div", {
38
- className: "bottom-buttons"
48
+ className: "top-buttons"
39
49
  }, React.createElement("button", {
40
50
  onClick: onRecalc,
41
51
  disabled: !recalcActive,
@@ -47,18 +57,58 @@ function PagesSelector(_ref2) {
47
57
  }, "Save")), React.createElement("div", {
48
58
  className: "pages"
49
59
  }, pages.map(function (page, idx) {
50
- return React.createElement(PageThumbnail, {
60
+ var _page$metadata;
61
+
62
+ return React.createElement("div", {
63
+ className: "page-thumbnail__wrapper"
64
+ }, React.createElement(PageThumbnail, {
51
65
  key: page.id,
52
66
  src: page.src,
53
67
  isActive: page.isActive,
54
68
  onClick: function onClick() {
55
69
  return onPageClick(idx);
56
70
  }
57
- });
58
- })));
71
+ }), showMetadata && React.createElement("div", {
72
+ className: "page-thumbnail__metadata"
73
+ }, React.createElement("h5", null, "Metadata"), page === null || page === void 0 ? void 0 : (_page$metadata = page.metadata) === null || _page$metadata === void 0 ? void 0 : _page$metadata.map(function (_ref3) {
74
+ var key = _ref3.key,
75
+ value = _ref3.value;
76
+ return React.createElement(React.Fragment, null, React.createElement("label", {
77
+ htmlFor: key
78
+ }, key), React.createElement("input", {
79
+ id: key,
80
+ type: "text",
81
+ value: value,
82
+ onChange: function onChange(e) {
83
+ return onMetadataChange({
84
+ name: key,
85
+ value: e.target.value,
86
+ imageIndex: idx
87
+ });
88
+ }
89
+ }));
90
+ })));
91
+ })), React.createElement("div", {
92
+ className: "bottom-buttons"
93
+ }, React.createElement("div", {
94
+ className: "show-metadata-wrapper"
95
+ }, React.createElement("label", {
96
+ className: "switch mr-2"
97
+ }, React.createElement("input", {
98
+ id: "show-metadata",
99
+ type: "checkbox",
100
+ value: showMetadata,
101
+ onChange: function onChange() {
102
+ return setShowMetadata(function (prev) {
103
+ return !prev;
104
+ });
105
+ }
106
+ }), React.createElement("span", {
107
+ className: "slider round"
108
+ })), React.createElement("label", null, "Metadata"))));
59
109
  }
60
110
 
61
- PagesSelector.defaultProps = {
111
+ PageSelector.defaultProps = {
62
112
  onPageClick: function onPageClick() {},
63
113
  onRecalc: function onRecalc() {},
64
114
  onSave: function onSave() {},
@@ -66,4 +116,4 @@ PagesSelector.defaultProps = {
66
116
  saveActive: false,
67
117
  pageNumber: undefined
68
118
  };
69
- export default PagesSelector;
119
+ export default PageSelector;
@@ -1,3 +1,4 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
1
2
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread";
2
3
  import React, { useRef, memo } from "react";
3
4
  import Paper from "@mui/material/Paper";
@@ -7,7 +8,8 @@ import styles from "./styles";
7
8
  import classnames from "classnames";
8
9
  import IconButton from "@mui/material/IconButton";
9
10
  import Button from "@mui/material/Button";
10
- import TrashIcon from "@mui/icons-material/Delete";
11
+ import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
12
+ import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
11
13
  import CheckIcon from "@mui/icons-material/Check";
12
14
  import TextField from "@mui/material/TextField";
13
15
  import Select from "react-select";
@@ -29,7 +31,8 @@ export var RegionLabel = function RegionLabel(_ref) {
29
31
  onRegionClassAdded = _ref.onRegionClassAdded,
30
32
  allowComments = _ref.allowComments,
31
33
  hideNotEditingLabel = _ref.hideNotEditingLabel,
32
- allowedGroups = _ref.allowedGroups;
34
+ allowedGroups = _ref.allowedGroups,
35
+ onDeleteGroup = _ref.onDeleteGroup;
33
36
  var classes = useStyles();
34
37
  var commentInputRef = useRef(null);
35
38
 
@@ -40,6 +43,12 @@ export var RegionLabel = function RegionLabel(_ref) {
40
43
  };
41
44
 
42
45
  if (hideNotEditingLabel && !editing) return null;
46
+ var allowedGroupsForSelect = allowedGroups.map(function (g) {
47
+ return {
48
+ value: "".concat(g),
49
+ label: "".concat(g)
50
+ };
51
+ });
43
52
  return React.createElement(ThemeProvider, {
44
53
  theme: theme
45
54
  }, React.createElement(Paper, {
@@ -99,7 +108,24 @@ export var RegionLabel = function RegionLabel(_ref) {
99
108
  },
100
109
  size: "small",
101
110
  variant: "outlined"
102
- }, React.createElement(TrashIcon, {
111
+ }, React.createElement(DeleteOutlineIcon, {
112
+ style: {
113
+ marginTop: -8,
114
+ width: 16,
115
+ height: 16
116
+ }
117
+ })), React.createElement(IconButton, {
118
+ onClick: function onClick() {
119
+ return onDeleteGroup(region.groupId);
120
+ },
121
+ tabIndex: -1,
122
+ style: {
123
+ width: 22,
124
+ height: 22
125
+ },
126
+ size: "small",
127
+ variant: "outlined"
128
+ }, React.createElement(DeleteForeverIcon, {
103
129
  style: {
104
130
  marginTop: -8,
105
131
  width: 16,
@@ -137,10 +163,10 @@ export var RegionLabel = function RegionLabel(_ref) {
137
163
  }));
138
164
  },
139
165
  placeholder: "Group",
140
- value: allowedGroups.filter(function (g) {
166
+ value: allowedGroupsForSelect.find(function (g) {
141
167
  return g.value === region.groupId;
142
168
  }),
143
- options: allowedGroups
169
+ options: _toConsumableArray(allowedGroupsForSelect)
144
170
  }), (allowedTags || []).length > 0 && React.createElement("div", {
145
171
  style: {
146
172
  marginTop: 4
@@ -11,8 +11,10 @@ var TransformGrabber = styled("div")(function (_ref) {
11
11
  return {
12
12
  width: 8,
13
13
  height: 8,
14
- zIndex: 2,
15
- border: "2px solid #FFF",
14
+ zIndex: 10,
15
+ backgroundColor: "#454545",
16
+ border: "2px solid black",
17
+ borderRadius: "50%",
16
18
  position: "absolute"
17
19
  };
18
20
  });
@@ -18,6 +18,7 @@ import VisibleOffIcon from "@mui/icons-material/VisibilityOff";
18
18
  import styles from "./styles";
19
19
  import classnames from "classnames";
20
20
  import isEqual from "lodash/isEqual";
21
+ import useColors from "../hooks/use-colors";
21
22
  var theme = createTheme();
22
23
  var useStyles = makeStyles(function (theme) {
23
24
  return styles;
@@ -151,6 +152,11 @@ var Row = function Row(_ref4) {
151
152
  color = _ref4.color,
152
153
  cls = _ref4.cls,
153
154
  index = _ref4.index;
155
+
156
+ var _useColors = useColors(),
157
+ groupColor = _useColors.groupColor;
158
+
159
+ var gc = groupColor(r.groupId);
154
160
  return React.createElement(RowLayout, {
155
161
  header: false,
156
162
  highlighted: highlighted,
@@ -160,7 +166,7 @@ var Row = function Row(_ref4) {
160
166
  order: "#".concat(index + 1),
161
167
  classification: React.createElement(Chip, {
162
168
  text: cls || "",
163
- color: color || "#ddd"
169
+ color: color || gc || "lime"
164
170
  }),
165
171
  area: "",
166
172
  trash: React.createElement(TrashIcon, {
@@ -56,7 +56,7 @@ var RegionComponents = {
56
56
  width: Math.max(region.w * iw, 0),
57
57
  height: Math.max(region.h * ih, 0),
58
58
  stroke: colorAlpha(clsColor(region.cls), 0.85),
59
- fill: region.groupHighlighted ? colorAlpha(groupColor(region.groupId), 0.85) : colorAlpha(groupColor(region.groupId), 0.5)
59
+ fill: region.groupHighlighted ? colorAlpha(clsColor(region.cls), 0.15) : colorAlpha(groupColor(region.groupId), 0.5)
60
60
  }));
61
61
  } else {
62
62
  return React.createElement("g", {
@@ -29,6 +29,7 @@ export var RegionTags = function RegionTags(_ref) {
29
29
  onChangeRegion = _ref.onChangeRegion,
30
30
  onCloseRegionEdit = _ref.onCloseRegionEdit,
31
31
  onDeleteRegion = _ref.onDeleteRegion,
32
+ onDeleteGroup = _ref.onDeleteGroup,
32
33
  layoutParams = _ref.layoutParams,
33
34
  imageSrc = _ref.imageSrc,
34
35
  RegionEditLabel = _ref.RegionEditLabel,
@@ -128,6 +129,7 @@ export var RegionTags = function RegionTags(_ref) {
128
129
  onChange: onChangeRegion,
129
130
  onClose: onCloseRegionEdit,
130
131
  onDelete: onDeleteRegion,
132
+ onDeleteGroup: onDeleteGroup,
131
133
  editing: region.editingLabels,
132
134
  region: region,
133
135
  regions: regions,
@@ -1,4 +1,5 @@
1
1
  import { useSettings } from "../SettingsProvider";
2
+ var DEFAULT_GROUP_COLOR = "#32CD32";
2
3
 
3
4
  function defaultClsColor(cls) {
4
5
  switch (cls) {
@@ -49,28 +50,6 @@ function defaultClsColor(cls) {
49
50
  }
50
51
  }
51
52
 
52
- function defaultGroupColor(groupId) {
53
- switch (groupId) {
54
- case "0":
55
- return "#FDDFDF";
56
-
57
- case "1":
58
- return "#FCF7DE";
59
-
60
- case "2":
61
- return "#DEFDE0";
62
-
63
- case "3":
64
- return "#DEF3FD";
65
-
66
- case "4":
67
- return "#F0DEFD";
68
-
69
- default:
70
- return "#F0DEFD";
71
- }
72
- }
73
-
74
53
  var useColors = function useColors() {
75
54
  var _useSettings = useSettings(),
76
55
  clsColors = _useSettings.clsColors,
@@ -84,12 +63,8 @@ var useColors = function useColors() {
84
63
  return defaultClsColor(cls);
85
64
  };
86
65
 
87
- var groupColor = function groupColor(groupId) {
88
- if (groupColors[groupId]) {
89
- return groupColors[groupId];
90
- }
91
-
92
- return defaultGroupColor(groupId);
66
+ var groupColor = function groupColor(idx) {
67
+ return groupColors[idx % groupColors.length] || DEFAULT_GROUP_COLOR;
93
68
  };
94
69
 
95
70
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@searpent/react-image-annotate",
3
- "version": "2.0.9",
3
+ "version": "2.0.12",
4
4
  "dependencies": {
5
5
  "@editorjs/editorjs": "^2.25.0",
6
6
  "@editorjs/paragraph": "^2.8.0",
@@ -1,46 +0,0 @@
1
- /**
2
- * Plugin styles
3
- */
4
- .ce-header {
5
- padding: 0.6em 0 3px;
6
- margin: 0;
7
- line-height: 1.25em;
8
- outline: none;
9
- }
10
-
11
- .ce-header p,
12
- .ce-header div {
13
- padding: 0 !important;
14
- margin: 0 !important;
15
- }
16
-
17
- /**
18
- * Styles for Plugin icon in Toolbar
19
- */
20
- .ce-header__icon {}
21
-
22
- .ce-header[contentEditable=true][data-placeholder]::before {
23
- position: absolute;
24
- content: attr(data-placeholder);
25
- color: #707684;
26
- font-weight: normal;
27
- display: none;
28
- cursor: text;
29
- }
30
-
31
- .ce-header[contentEditable=true][data-placeholder]:empty::before {
32
- display: block;
33
- }
34
-
35
- .ce-header[contentEditable=true][data-placeholder]:empty:focus::before {
36
- display: none;
37
- }
38
-
39
- /* Custom overwrite */
40
- .cdx-settings-button {
41
- width: 100% !important;
42
- }
43
-
44
- .ce-settings__plugin-zone {
45
- padding: 0 .25rem;
46
- }
@@ -1,87 +0,0 @@
1
- .page-selector {
2
- height: 100vh;
3
- overflow-y: scroll;
4
- width: 10%;
5
- }
6
-
7
- .pages {
8
- list-style: none;
9
- padding: 1rem;
10
- }
11
-
12
- .page-thumbnail {
13
- margin-bottom: 1rem;
14
- border-radius: .25rem !important;
15
- overflow: hidden;
16
- filter: grayscale(1);
17
- transition: transform .2s;
18
- opacity: .5;
19
- }
20
-
21
- .page-thumbnail:hover {
22
- box-shadow: 0 0 2rem 0 #8898aa !important;
23
- filter: grayscale(0);
24
- cursor: pointer;
25
- opacity: 1;
26
- }
27
-
28
- .page-thumbnail-is-active {
29
- filter: grayscale(0);
30
- opacity: 1;
31
- }
32
-
33
- .page-thumbnail img {
34
- width: 100%;
35
- }
36
-
37
- .bottom-buttons {
38
- background: linear-gradient(#8898aa, rgba(255, 255, 255, 0));
39
- position: sticky;
40
- top: 0;
41
- display: flex;
42
- flex-direction: column;
43
- padding: 1rem;
44
- margin-bottom: 1rem;
45
- z-index: 100;
46
- }
47
-
48
- .bottom-buttons button {
49
- margin-bottom: 1rem;
50
- width: 100%;
51
- }
52
-
53
- .bottom-buttons button.info {
54
- background-color: transparent;
55
- border-radius: 0.5rem;
56
- background-image: linear-gradient(310deg, #627594, #a8b8d8);
57
- color: white;
58
- border: none;
59
- padding: 0.5rem 0;
60
- }
61
-
62
- .bottom-buttons button.success {
63
- color: white;
64
- background-image: linear-gradient(310deg, #2dce89, #2dcecc);
65
- border-radius: 0.5rem;
66
- border: none;
67
- padding: 0.5rem 0;
68
- }
69
-
70
-
71
- .page-number-wrapper {
72
- position: absolute;
73
- bottom: 0;
74
- width: 100%;
75
- height: 10%;
76
- z-index: 100;
77
- display: flex;
78
- justify-content: center;
79
- align-items: center;
80
- background: linear-gradient(rgba(255, 255, 255, 0), #8898aa);
81
- padding: .5rem 0;
82
- }
83
-
84
- .page-number {
85
- font-size: 1.5rem;
86
- font-weight: 800;
87
- }