@searpent/react-image-annotate 2.0.77 → 2.0.79

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/Annotator/exampleImages.js +41 -0
  2. package/Annotator/examplePhotos.js +6980 -0
  3. package/Annotator/index.js +417 -0
  4. package/Annotator/reducers/combine-reducers.js +14 -0
  5. package/Annotator/reducers/convert-expanding-line-to-polygon.js +73 -0
  6. package/{src/Annotator → Annotator}/reducers/fix-twisted.js +3 -5
  7. package/Annotator/reducers/general-reducer.js +1430 -0
  8. package/Annotator/reducers/get-active-image.js +27 -0
  9. package/Annotator/reducers/get-implied-video-regions.js +180 -0
  10. package/Annotator/reducers/history-handler.js +38 -0
  11. package/Annotator/reducers/image-reducer.js +20 -0
  12. package/Annotator/reducers/video-reducer.js +88 -0
  13. package/ClassSelectionMenu/index.js +140 -0
  14. package/Crosshairs/index.js +53 -0
  15. package/DebugSidebarBox/index.js +20 -0
  16. package/DemoSite/Editor.js +194 -0
  17. package/DemoSite/ErrorBoundaryDialog.js +64 -0
  18. package/DemoSite/index.js +40 -0
  19. package/Editor/annotation-plugin/annotation.js +702 -0
  20. package/Editor/index.js +93 -0
  21. package/Editor/readOnly.js +123 -0
  22. package/{src/Editor → Editor}/tools.js +2 -3
  23. package/Errorer/index.js +11 -0
  24. package/FullImageSegmentationAnnotator/index.js +7 -0
  25. package/GroupSelectorSidebarBox/index.js +63 -0
  26. package/GroupsEditorSidebarBox/index.js +138 -0
  27. package/HelpSidebarBox/index.js +58 -0
  28. package/HighlightBox/index.js +102 -0
  29. package/HistorySidebarBox/index.js +71 -0
  30. package/ImageCanvas/index.js +441 -0
  31. package/ImageCanvas/region-tools.js +165 -0
  32. package/{src/ImageCanvas → ImageCanvas}/styles.js +12 -8
  33. package/ImageCanvas/use-mouse.js +180 -0
  34. package/ImageCanvas/use-project-box.js +27 -0
  35. package/ImageCanvas/use-wasd-mode.js +62 -0
  36. package/ImageMask/index.js +133 -0
  37. package/ImageMask/load-image.js +25 -0
  38. package/ImageSelectorSidebarBox/index.js +60 -0
  39. package/KeyframeTimeline/get-time-string.js +27 -0
  40. package/KeyframeTimeline/index.js +233 -0
  41. package/KeyframesSelectorSidebarBox/index.js +93 -0
  42. package/LandingPage/index.js +159 -0
  43. package/Locker/index.js +11 -0
  44. package/MainLayout/RightSidebarItemsWrapper.js +19 -0
  45. package/MainLayout/icon-dictionary.js +104 -0
  46. package/MainLayout/index.js +526 -0
  47. package/{src/MainLayout → MainLayout}/styles.js +6 -7
  48. package/MainLayout/types.js +0 -0
  49. package/MainLayout/use-implied-video-regions.js +13 -0
  50. package/MetadataEditorSidebarBox/index.js +231 -0
  51. package/PageSelector/index.js +180 -0
  52. package/PointDistances/index.js +73 -0
  53. package/PreventScrollToParents/index.js +51 -0
  54. package/RegionLabel/index.js +232 -0
  55. package/{src/RegionLabel → RegionLabel}/styles.js +12 -15
  56. package/RegionSelectAndTransformBoxes/index.js +169 -0
  57. package/RegionSelectorSidebarBox/index.js +254 -0
  58. package/{src/RegionSelectorSidebarBox → RegionSelectorSidebarBox}/styles.js +13 -14
  59. package/RegionShapes/index.js +294 -0
  60. package/RegionTags/index.js +144 -0
  61. package/SettingsDialog/index.js +52 -0
  62. package/SettingsProvider/index.js +60 -0
  63. package/Shortcuts/ShortcutField.js +46 -0
  64. package/Shortcuts/index.js +133 -0
  65. package/ShortcutsManager/index.js +155 -0
  66. package/Sidebar/index.js +69 -0
  67. package/SidebarBoxContainer/index.js +93 -0
  68. package/SmallToolButton/index.js +42 -0
  69. package/TagsSidebarBox/index.js +105 -0
  70. package/TaskDescriptionSidebarBox/index.js +58 -0
  71. package/Theme/index.js +30 -0
  72. package/VideoOrImageCanvasBackground/index.js +151 -0
  73. package/colors.js +14 -0
  74. package/hooks/use-colors.js +127 -0
  75. package/hooks/use-event-callback.js +10 -0
  76. package/hooks/use-exclude-pattern.js +24 -0
  77. package/hooks/use-load-image.js +26 -0
  78. package/hooks/use-window-size.js +46 -0
  79. package/{src/hooks → hooks}/xpattern.js +1 -1
  80. package/index.js +3 -0
  81. package/lib.js +3 -0
  82. package/package.json +1 -1
  83. package/stories.js +5 -0
  84. package/utils/blocks-to-article.js +60 -0
  85. package/{src/utils → utils}/blocks-to-article.test.js +5 -8
  86. package/{src/utils → utils}/default-locked-until.js +2 -1
  87. package/{src/utils → utils}/filter-only-unique.js +1 -1
  88. package/utils/get-from-local-storage.js +7 -0
  89. package/utils/get-hotkey-help-text.js +9 -0
  90. package/utils/get-landmarks-with-transform.js +40 -0
  91. package/utils/photosToImages.js +85 -0
  92. package/utils/regions-groups.js +28 -0
  93. package/utils/regions-to-blocks.js +18 -0
  94. package/utils/saveable-actions-enum.js +3 -0
  95. package/utils/set-in-local-storage.js +3 -0
  96. package/utils/sleep.js +7 -0
  97. package/utils/uuid-to-hash.js +5 -0
  98. package/.babelrc +0 -6
  99. package/.env +0 -1
  100. package/.flowconfig +0 -2
  101. package/.github/workflows/release-on-master.yml +0 -32
  102. package/.github/workflows/test.yml +0 -16
  103. package/.prettierrc +0 -3
  104. package/.releaserc.js +0 -18
  105. package/.storybook/addons.js +0 -2
  106. package/.storybook/config.js +0 -16
  107. package/LICENSE +0 -21
  108. package/public/favicon.ico +0 -0
  109. package/public/index.html +0 -38
  110. package/src/Annotator/bike-pic.png +0 -0
  111. package/src/Annotator/bike-pic2.png +0 -0
  112. package/src/Annotator/dab-keyframes.story.json +0 -1
  113. package/src/Annotator/exampleImages.js +0 -48
  114. package/src/Annotator/examplePhotos.js +0 -7603
  115. package/src/Annotator/index.js +0 -380
  116. package/src/Annotator/index.story.js +0 -899
  117. package/src/Annotator/poses.story.js +0 -150
  118. package/src/Annotator/reducers/combine-reducers.js +0 -7
  119. package/src/Annotator/reducers/convert-expanding-line-to-polygon.js +0 -53
  120. package/src/Annotator/reducers/general-reducer.js +0 -1228
  121. package/src/Annotator/reducers/get-active-image.js +0 -21
  122. package/src/Annotator/reducers/get-implied-video-regions.js +0 -115
  123. package/src/Annotator/reducers/history-handler.js +0 -60
  124. package/src/Annotator/reducers/image-reducer.js +0 -23
  125. package/src/Annotator/reducers/video-reducer.js +0 -85
  126. package/src/Annotator/video.story.js +0 -51
  127. package/src/ClassSelectionMenu/index.js +0 -112
  128. package/src/Crosshairs/index.js +0 -64
  129. package/src/DebugSidebarBox/index.js +0 -36
  130. package/src/DemoSite/Editor.js +0 -235
  131. package/src/DemoSite/ErrorBoundaryDialog.js +0 -34
  132. package/src/DemoSite/index.js +0 -41
  133. package/src/DemoSite/index.story.js +0 -10
  134. package/src/DemoSite/simple-segmentation-example.json +0 -572
  135. package/src/Editor/annotation-plugin/annotation.js +0 -546
  136. package/src/Editor/index.js +0 -50
  137. package/src/Editor/readOnly.js +0 -31
  138. package/src/Errorer/index.js +0 -13
  139. package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
  140. package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
  141. package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
  142. package/src/FullImageSegmentationAnnotator/index.js +0 -7
  143. package/src/FullImageSegmentationAnnotator/index.story.js +0 -177
  144. package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
  145. package/src/GroupSelectorSidebarBox/index.js +0 -48
  146. package/src/GroupsEditorSidebarBox/index.js +0 -108
  147. package/src/HelpSidebarBox/index.js +0 -43
  148. package/src/HighlightBox/index.js +0 -143
  149. package/src/HistorySidebarBox/index.js +0 -78
  150. package/src/ImageCanvas/dancing-man.story.jpg +0 -0
  151. package/src/ImageCanvas/index.js +0 -515
  152. package/src/ImageCanvas/index.story.js +0 -314
  153. package/src/ImageCanvas/mouse_mask.story.png +0 -0
  154. package/src/ImageCanvas/region-tools.js +0 -171
  155. package/src/ImageCanvas/seves_desk.story.jpg +0 -0
  156. package/src/ImageCanvas/use-mouse.js +0 -168
  157. package/src/ImageCanvas/use-project-box.js +0 -23
  158. package/src/ImageCanvas/use-wasd-mode.js +0 -50
  159. package/src/ImageMask/index.js +0 -127
  160. package/src/ImageMask/load-image.js +0 -32
  161. package/src/ImageSelectorSidebarBox/index.js +0 -54
  162. package/src/KeyframeTimeline/get-time-string.js +0 -25
  163. package/src/KeyframeTimeline/index.js +0 -223
  164. package/src/KeyframesSelectorSidebarBox/index.js +0 -93
  165. package/src/LandingPage/content.md +0 -57
  166. package/src/LandingPage/github-markdown.css +0 -964
  167. package/src/LandingPage/index.js +0 -147
  168. package/src/Locker/index.js +0 -13
  169. package/src/MainLayout/RightSidebarItemsWrapper.js +0 -21
  170. package/src/MainLayout/icon-dictionary.js +0 -79
  171. package/src/MainLayout/index.js +0 -564
  172. package/src/MainLayout/index.story.js +0 -240
  173. package/src/MainLayout/types.js +0 -171
  174. package/src/MainLayout/use-implied-video-regions.js +0 -17
  175. package/src/MetadataEditorSidebarBox/index.js +0 -160
  176. package/src/PageSelector/index.js +0 -159
  177. package/src/PointDistances/index.js +0 -90
  178. package/src/PreventScrollToParents/index.js +0 -48
  179. package/src/PreventScrollToParents/index.story.js +0 -23
  180. package/src/RegionLabel/index.js +0 -236
  181. package/src/RegionSelectAndTransformBoxes/index.js +0 -236
  182. package/src/RegionSelectorSidebarBox/index.js +0 -220
  183. package/src/RegionShapes/index.js +0 -254
  184. package/src/RegionTags/index.js +0 -136
  185. package/src/SettingsDialog/index.js +0 -58
  186. package/src/SettingsProvider/index.js +0 -57
  187. package/src/Shortcuts/ShortcutField.js +0 -44
  188. package/src/Shortcuts/index.js +0 -129
  189. package/src/ShortcutsManager/index.js +0 -162
  190. package/src/Sidebar/index.js +0 -117
  191. package/src/SidebarBoxContainer/index.js +0 -93
  192. package/src/SmallToolButton/index.js +0 -57
  193. package/src/TagsSidebarBox/index.js +0 -93
  194. package/src/TaskDescriptionSidebarBox/index.js +0 -43
  195. package/src/Theme/index.js +0 -36
  196. package/src/VideoOrImageCanvasBackground/index.js +0 -170
  197. package/src/colors.js +0 -32
  198. package/src/hooks/use-colors.js +0 -95
  199. package/src/hooks/use-event-callback.js +0 -11
  200. package/src/hooks/use-exclude-pattern.js +0 -27
  201. package/src/hooks/use-load-image.js +0 -21
  202. package/src/hooks/use-window-size.js +0 -46
  203. package/src/hooks/xpattern.png +0 -0
  204. package/src/index.js +0 -18
  205. package/src/lib.js +0 -7
  206. package/src/screenshot.png +0 -0
  207. package/src/site.css +0 -5
  208. package/src/stories.js +0 -2
  209. package/src/utils/blocks-to-article.js +0 -61
  210. package/src/utils/get-from-local-storage.js +0 -7
  211. package/src/utils/get-hotkey-help-text.js +0 -11
  212. package/src/utils/get-landmarks-with-transform.js +0 -23
  213. package/src/utils/photosToImages.js +0 -67
  214. package/src/utils/regions-groups.js +0 -19
  215. package/src/utils/regions-to-blocks.js +0 -16
  216. package/src/utils/saveable-actions-enum.js +0 -5
  217. package/src/utils/set-in-local-storage.js +0 -6
  218. package/src/utils/sleep.js +0 -3
  219. package/src/utils/uuid-to-hash.js +0 -5
  220. /package/{src/Editor → Editor}/annotation-plugin/annotation.css +0 -0
  221. /package/{src/Errorer → Errorer}/errorer.css +0 -0
  222. /package/{src/Locker → Locker}/locker.css +0 -0
  223. /package/{src/PageSelector → PageSelector}/page-selector.css +0 -0
  224. /package/{src/utils → utils}/next-group-id.js +0 -0
@@ -1,159 +0,0 @@
1
- import React, { useState } from 'react';
2
- import PropTypes from 'prop-types';
3
- import classnames from "classnames"
4
- import './page-selector.css';
5
- import Locker from '../Locker';
6
- import Errorer from '../Errorer';
7
-
8
- function PageThumbnail({ src, isActive, onClick, metadata, showMetadata, imageIndex, imageId, onMetadataChange, metadataConfigs = [], isLocked, error, onRecalcClick, isRecalcReady = false }) {
9
- const handleChange = e => {
10
- e.preventDefault()
11
- const { name, value } = e.target
12
- onMetadataChange({
13
- name,
14
- value,
15
- imageIndex
16
- })
17
- }
18
-
19
- const handleRecalcClick = e => {
20
- e.stopPropagation();
21
- onRecalcClick({ imageId })
22
- }
23
-
24
- const pageNumber = metadata?.find?.(md => md.key === 'pageNumber')?.value
25
-
26
- return (
27
- <div
28
- role="button"
29
- tabIndex={0}
30
- className={classnames('ps-page-thumbnail', {
31
- 'ps-page-thumbnail-is-active': isActive,
32
- })}
33
- onClick={onClick}
34
- >
35
- {
36
- isLocked && (
37
- <Locker />
38
- )
39
- }
40
- {
41
- error && (
42
- <Errorer errorMessage={error.message} />
43
- )
44
- }
45
- <div className="ps-page-thumbnail-image-wrapper">
46
- {
47
- isRecalcReady && (
48
- <div className="ps-page-thumbnail-recalc-wrapper">
49
- <button className="recalc-button" onClick={handleRecalcClick}>Extract</button>
50
- </div>
51
- )
52
- }
53
- <img src={src} alt="" className="ps-page-thumbnail-image" />
54
- <div className="page-number-wrapper">
55
- {
56
- (pageNumber !== undefined && !showMetadata) && (
57
- <span className="page-number">{pageNumber}</span>
58
- )
59
- }
60
- </div>
61
- </div>
62
- <div className="ps-page-thumbnail-metadata-wrapper">
63
- {
64
- metadata.map(({ key, value }) => (<>
65
- <label for={key}>{key}</label>
66
- <input type="text" value={value} name={key} onChange={handleChange} onClick={e => e.stopPropagation()} id={key} list={`${key}-list`} />
67
- <datalist id={`${key}-list`}>
68
- {
69
- metadataConfigs.find(mcf => mcf.key === key)?.options.map(opt => <option key={opt} value={opt}></option>)
70
- }
71
- </datalist>
72
- </>))
73
- }
74
- </div>
75
- </div >
76
- );
77
- }
78
-
79
- function isLocked(page) {
80
- const { lockedUntil } = page;
81
-
82
- // needs to be defined and greater than current time
83
- if (Date.parse(lockedUntil)?.valueOf() > new Date().valueOf()) {
84
- return true
85
- }
86
-
87
- return false;
88
- }
89
-
90
- function PageSelector({ pages, onPageClick, onMetadataChange, metadataConfigs, onRecalcClick }) {
91
- const [showMetadata, setShowMetadata] = useState(false);
92
-
93
- return (
94
- <div className={classnames('page-selector', {
95
- 'page-selector--opened': showMetadata,
96
- })}>
97
- <div className="top-buttons">
98
- <div className="show-metadata-wrapper">
99
- <label className="switch mr-2">
100
- <input id="show-metadata" type="checkbox" value={showMetadata} onChange={() => setShowMetadata(prev => !prev)} />
101
- <span className="slider round"></span>
102
- </label>
103
- <label>Metadata</label>
104
- </div>
105
- </div>
106
- <div className="pages">
107
- {pages.map((page, idx) => (
108
- <PageThumbnail
109
- key={`${page.id}`}
110
- isLocked={isLocked(page)}
111
- error={page.syncError}
112
- src={page.src}
113
- isActive={page.isActive}
114
- onClick={() => onPageClick(idx)}
115
- metadata={page.metadata}
116
- showMetadata={showMetadata}
117
- imageIndex={idx}
118
- imageId={page.id}
119
- onMetadataChange={onMetadataChange}
120
- metadataConfigs={metadataConfigs}
121
- onRecalcClick={onRecalcClick}
122
- isRecalcReady={page.isRecalcReady}
123
- />
124
- ))
125
- }
126
- </div >
127
- </div >
128
- );
129
- }
130
-
131
- PageSelector.propTypes = {
132
- pages: PropTypes.arrayOf(
133
- PropTypes.shape({
134
- id: PropTypes.string.isRequired,
135
- src: PropTypes.string.isRequired,
136
- isActive: PropTypes.bool.isRequired,
137
- pageNumber: PropTypes.string
138
- })
139
- ).isRequired,
140
- onPageClick: PropTypes.func,
141
- recalcActive: PropTypes.bool,
142
- saveActive: PropTypes.bool,
143
- pageNumber: PropTypes.string,
144
- onMetadataChange: PropTypes.func.isRequired,
145
- metadataConfigs: PropTypes.arrayOf(PropTypes.shape({
146
- key: PropTypes.string.isRequired,
147
- level: PropTypes.string.isRequired,
148
- options: PropTypes.arrayOf(PropTypes.string).isRequired,
149
- }))
150
- };
151
-
152
- PageSelector.defaultProps = {
153
- onPageClick: () => { },
154
- recalcActive: false,
155
- saveActive: false,
156
- pageNumber: undefined
157
- };
158
-
159
- export default PageSelector;
@@ -1,90 +0,0 @@
1
- // @flow weak
2
-
3
- import React, { Fragment } from "react"
4
- import { styled } from "@mui/material/styles"
5
- import { createTheme, ThemeProvider } from "@mui/material/styles"
6
-
7
- const theme = createTheme()
8
- const Svg = styled("svg")(({ theme }) => ({
9
- pointerEvents: "none",
10
- position: "absolute",
11
- zIndex: 1,
12
- left: 0,
13
- top: 0,
14
- width: "100%",
15
- height: "100%",
16
- "& text": {
17
- fill: "#fff",
18
- },
19
- "& path": {
20
- vectorEffect: "non-scaling-stroke",
21
- strokeWidth: 2,
22
- opacity: 0.5,
23
- stroke: "#FFF",
24
- fill: "none",
25
- strokeDasharray: 5,
26
- animationDuration: "4s",
27
- animationTimingFunction: "linear",
28
- animationIterationCount: "infinite",
29
- animationPlayState: "running",
30
- },
31
- }))
32
-
33
- export const PointDistances = ({
34
- projectRegionBox,
35
- regions,
36
- pointDistancePrecision,
37
- realSize,
38
- }) => {
39
- return (
40
- <ThemeProvider theme={theme}>
41
- <Svg>
42
- {regions
43
- .filter((r1) => r1.type === "point")
44
- .flatMap((r1, i1) =>
45
- regions
46
- .filter((r2, i2) => i2 > i1)
47
- .filter((r2) => r2.type === "point")
48
- .map((r2) => {
49
- const pr1 = projectRegionBox(r1)
50
- const pr2 = projectRegionBox(r2)
51
- const prm = {
52
- x: (pr1.x + pr1.w / 2 + pr2.x + pr2.w / 2) / 2,
53
- y: (pr1.y + pr1.h / 2 + pr2.y + pr2.h / 2) / 2,
54
- }
55
- let displayDistance
56
- if (realSize) {
57
- const { w, h, unitName } = realSize
58
- displayDistance =
59
- Math.sqrt(
60
- Math.pow(r1.x * w - r2.x * w, 2) +
61
- Math.pow(r1.y * h - r2.y * h, 2)
62
- ).toFixed(pointDistancePrecision) + unitName
63
- } else {
64
- displayDistance =
65
- (
66
- Math.sqrt(
67
- Math.pow(r1.x - r2.x, 2) + Math.pow(r1.y - r2.y, 2)
68
- ) * 100
69
- ).toFixed(pointDistancePrecision) + "%"
70
- }
71
- return (
72
- <Fragment>
73
- <path
74
- d={`M${pr1.x + pr1.w / 2},${pr1.y + pr1.h / 2} L${
75
- pr2.x + pr2.w / 2
76
- },${pr2.y + pr2.h / 2}`}
77
- />
78
- <text x={prm.x} y={prm.y}>
79
- {displayDistance}
80
- </text>
81
- </Fragment>
82
- )
83
- })
84
- )}
85
- </Svg>
86
- </ThemeProvider>
87
- )
88
- }
89
-
90
- export default PointDistances
@@ -1,48 +0,0 @@
1
- // @flow
2
-
3
- import React, { useState } from "react"
4
- import { RemoveScroll } from "react-remove-scroll"
5
- import { styled } from "@mui/material/styles"
6
- import { createTheme, ThemeProvider } from "@mui/material/styles"
7
- import useEventCallback from "use-event-callback"
8
-
9
- const theme = createTheme()
10
- const Container = styled("div")(({ theme }) => ({
11
- "& > div": {
12
- width: "100%",
13
- height: "100%",
14
- },
15
- }))
16
-
17
- export const PreventScrollToParents = ({ children, ...otherProps }) => {
18
- const [mouseOver, changeMouseOver] = useState(false)
19
- const onMouseMove = useEventCallback((e) => {
20
- if (!mouseOver) changeMouseOver(true)
21
- if (otherProps.onMouseMove) {
22
- otherProps.onMouseMove(e)
23
- }
24
- })
25
- const onMouseLeave = useEventCallback((e) => {
26
- setTimeout(() => {
27
- if (mouseOver) {
28
- changeMouseOver(false)
29
- }
30
- }, 100)
31
- })
32
-
33
- return (
34
- <ThemeProvider theme={theme}>
35
- <Container
36
- {...otherProps}
37
- onMouseMove={onMouseMove}
38
- onMouseLeave={onMouseLeave}
39
- >
40
- <RemoveScroll enabled={mouseOver} removeScrollBar={false}>
41
- {children}
42
- </RemoveScroll>
43
- </Container>
44
- </ThemeProvider>
45
- )
46
- }
47
-
48
- export default PreventScrollToParents
@@ -1,23 +0,0 @@
1
- // @flow
2
-
3
- import React from "react"
4
-
5
- import { storiesOf } from "@storybook/react"
6
- import { action } from "@storybook/addon-actions"
7
-
8
- import RemoveScrollOnChildren from "./"
9
-
10
- storiesOf("RemoveScrollOnChildren", module).add("Basic", () => (
11
- <div style={{ width: "100vh", textAlign: "center", height: "200vh" }}>
12
- <RemoveScrollOnChildren>
13
- <div
14
- style={{
15
- display: "inline-block",
16
- width: 100,
17
- height: 100,
18
- backgroundColor: "red",
19
- }}
20
- />
21
- </RemoveScrollOnChildren>
22
- </div>
23
- ))
@@ -1,236 +0,0 @@
1
- // @flow
2
-
3
- import React, { useRef, memo } from "react"
4
- import Paper from "@mui/material/Paper"
5
- import { makeStyles } from "@mui/styles"
6
- import { createTheme, ThemeProvider } from "@mui/material/styles"
7
- import styles from "./styles"
8
- import classnames from "classnames"
9
- import type { Region } from "../ImageCanvas/region-tools.js"
10
- import IconButton from "@mui/material/IconButton"
11
- import Button from "@mui/material/Button"
12
- import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
13
- import DeleteForeverIcon from '@mui/icons-material/DeleteForever';
14
- import CheckIcon from "@mui/icons-material/Check"
15
- import TextField from "@mui/material/TextField"
16
- import Select from "react-select"
17
- import CreatableSelect from "react-select/creatable"
18
- import uuidToHash from '../utils/uuid-to-hash';
19
-
20
- import { asMutable } from "seamless-immutable"
21
-
22
- const theme = createTheme()
23
- const useStyles = makeStyles((theme) => styles)
24
-
25
- type Props = {
26
- region: Region,
27
- editing?: boolean,
28
- allowedClasses?: Array<string>,
29
- allowedTags?: Array<string>,
30
- allowedGroups?: Array<{ value: String, label: String }>,
31
- cls?: string,
32
- tags?: Array<string>,
33
- onDelete: (Region) => null,
34
- onDeleteGroup: (string) => null,
35
- onChange: (Region) => null,
36
- onClose: (Region) => null,
37
- onOpen: (Region) => null,
38
- onRegionClassAdded: () => {},
39
- allowComments?: boolean,
40
- hideNotEditingLabel?: boolean,
41
- }
42
-
43
- export const RegionLabel = ({
44
- region,
45
- editing,
46
- allowedClasses,
47
- allowedTags,
48
- onDelete,
49
- onChange,
50
- onClose,
51
- onOpen,
52
- onRegionClassAdded,
53
- allowComments,
54
- hideNotEditingLabel,
55
- allowedGroups,
56
- onDeleteGroup
57
- }: Props) => {
58
- const classes = useStyles()
59
- const commentInputRef = useRef(null)
60
- const onCommentInputClick = (_) => {
61
- // The TextField wraps the <input> tag with two divs
62
- const commentInput = commentInputRef.current.children[0].children[0]
63
-
64
- if (commentInput) return commentInput.focus()
65
- }
66
-
67
- if (hideNotEditingLabel && !editing) return null
68
- const allowedGroupsForSelect = allowedGroups ? allowedGroups.map(g => ({
69
- value: `${g.id}`,
70
- label: g.label || uuidToHash(g.id)
71
- })) : []
72
-
73
- return (
74
- <ThemeProvider theme={theme}>
75
- <Paper
76
- onClick={() => (!editing ? onOpen(region) : null)}
77
- className={classnames(classes.regionInfo, {
78
- highlighted: region.highlighted,
79
- })}
80
- >
81
- {!editing ? (
82
- <div>
83
- {region.cls && (
84
- <div className="name">
85
- <div
86
- className="circle"
87
- style={{ backgroundColor: region.color }}
88
- />
89
- {region.cls}
90
- </div>
91
- )}
92
- {region.tags && (
93
- <div className="tags">
94
- {region.tags.map((t) => (
95
- <div key={t} className="tag">
96
- {t}
97
- </div>
98
- ))}
99
- </div>
100
- )}
101
- </div>
102
- ) : (
103
- <div style={{ width: 200 }}>
104
- <div style={{ display: "flex", flexDirection: "row" }}>
105
- <div
106
- style={{
107
- display: "flex",
108
- backgroundColor: region.color || "#888",
109
- color: "#fff",
110
- padding: 4,
111
- paddingLeft: 8,
112
- paddingRight: 8,
113
- borderRadius: 4,
114
- fontWeight: "bold",
115
- textShadow: "0px 0px 5px rgba(0,0,0,0.4)",
116
- }}
117
- >
118
- {region.type}
119
- </div>
120
- <div style={{ flexGrow: 1 }} />
121
- <IconButton
122
- onClick={() => onDelete(region)}
123
- tabIndex={-1}
124
- style={{ width: 22, height: 22 }}
125
- size="small"
126
- variant="outlined"
127
- >
128
- <DeleteOutlineIcon style={{ marginTop: -8, width: 16, height: 16 }} />
129
- </IconButton>
130
- <IconButton
131
- onClick={() => onDeleteGroup(region.groupId)}
132
- tabIndex={-1}
133
- style={{ width: 22, height: 22 }}
134
- size="small"
135
- variant="outlined"
136
- >
137
- <DeleteForeverIcon style={{ marginTop: -8, width: 16, height: 16 }} />
138
- </IconButton>
139
- </div>
140
- {(allowedClasses || []).length > 0 && (
141
- <div style={{ marginTop: 6 }}>
142
- <CreatableSelect
143
- placeholder="Classification"
144
- onChange={(o, actionMeta) => {
145
- if (actionMeta.action == "create-option") {
146
- onRegionClassAdded(o.value)
147
- }
148
- return onChange({
149
- ...(region: any),
150
- cls: o.value,
151
- })
152
- }}
153
- value={
154
- region.cls ? { label: region.cls, value: region.cls } : null
155
- }
156
- options={asMutable(
157
- allowedClasses.map((c) => ({ value: c, label: c }))
158
- )}
159
- />
160
- </div>
161
- )}
162
- {(allowedGroups || []).length > 0 && (
163
- <Select
164
- onChange={(newGroup) => onChange({
165
- ...(region: any),
166
- groupId: newGroup.value,
167
- })}
168
- placeholder="Group"
169
- value={allowedGroupsForSelect.find(g => g.value === region.groupId)
170
- }
171
- options={[...allowedGroupsForSelect]}
172
- />
173
- )}
174
- {(allowedTags || []).length > 0 && (
175
- <div style={{ marginTop: 4 }}>
176
- <Select
177
- onChange={(newTags) =>
178
- onChange({
179
- ...(region: any),
180
- tags: newTags.map((t) => t.value),
181
- })
182
- }
183
- placeholder="Tags"
184
- value={(region.tags || []).map((c) => ({
185
- label: c,
186
- value: c,
187
- }))}
188
- isMulti
189
- options={asMutable(
190
- allowedTags.map((c) => ({ value: c, label: c }))
191
- )}
192
- />
193
- </div>
194
- )}
195
- {allowComments && (
196
- <TextField
197
- InputProps={{
198
- className: classes.commentBox,
199
- }}
200
- fullWidth
201
- multiline
202
- rows={3}
203
- ref={commentInputRef}
204
- onClick={onCommentInputClick}
205
- value={region.comment || ""}
206
- onChange={(event) =>
207
- onChange({ ...(region: any), comment: event.target.value })
208
- }
209
- />
210
- )}
211
- {onClose && (
212
- <div style={{ marginTop: 4, display: "flex" }}>
213
- <div style={{ flexGrow: 1 }} />
214
- <Button
215
- onClick={() => onClose(region)}
216
- size="small"
217
- variant="contained"
218
- color="primary"
219
- >
220
- <CheckIcon />
221
- </Button>
222
- </div>
223
- )}
224
- </div>
225
- )}
226
- </Paper>
227
- </ThemeProvider>
228
- )
229
- }
230
-
231
- export default memo(
232
- RegionLabel,
233
- (prevProps, nextProps) =>
234
- prevProps.editing === nextProps.editing &&
235
- prevProps.region === nextProps.region
236
- )