@searpent/react-image-annotate 2.0.76 → 2.0.78

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/{src/Editor → Editor}/annotation-plugin/annotation.css +20 -0
  20. package/Editor/annotation-plugin/annotation.js +697 -0
  21. package/Editor/index.js +93 -0
  22. package/Editor/readOnly.js +123 -0
  23. package/{src/Editor → Editor}/tools.js +2 -3
  24. package/Errorer/index.js +11 -0
  25. package/FullImageSegmentationAnnotator/index.js +7 -0
  26. package/GroupSelectorSidebarBox/index.js +63 -0
  27. package/GroupsEditorSidebarBox/index.js +138 -0
  28. package/HelpSidebarBox/index.js +58 -0
  29. package/HighlightBox/index.js +102 -0
  30. package/HistorySidebarBox/index.js +71 -0
  31. package/ImageCanvas/index.js +441 -0
  32. package/ImageCanvas/region-tools.js +165 -0
  33. package/{src/ImageCanvas → ImageCanvas}/styles.js +12 -8
  34. package/ImageCanvas/use-mouse.js +180 -0
  35. package/ImageCanvas/use-project-box.js +27 -0
  36. package/ImageCanvas/use-wasd-mode.js +62 -0
  37. package/ImageMask/index.js +133 -0
  38. package/ImageMask/load-image.js +25 -0
  39. package/ImageSelectorSidebarBox/index.js +60 -0
  40. package/KeyframeTimeline/get-time-string.js +27 -0
  41. package/KeyframeTimeline/index.js +233 -0
  42. package/KeyframesSelectorSidebarBox/index.js +93 -0
  43. package/LandingPage/index.js +159 -0
  44. package/Locker/index.js +11 -0
  45. package/MainLayout/RightSidebarItemsWrapper.js +19 -0
  46. package/MainLayout/icon-dictionary.js +104 -0
  47. package/MainLayout/index.js +526 -0
  48. package/{src/MainLayout → MainLayout}/styles.js +6 -7
  49. package/MainLayout/types.js +0 -0
  50. package/MainLayout/use-implied-video-regions.js +13 -0
  51. package/MetadataEditorSidebarBox/index.js +231 -0
  52. package/PageSelector/index.js +180 -0
  53. package/PointDistances/index.js +73 -0
  54. package/PreventScrollToParents/index.js +51 -0
  55. package/RegionLabel/index.js +232 -0
  56. package/{src/RegionLabel → RegionLabel}/styles.js +12 -15
  57. package/RegionSelectAndTransformBoxes/index.js +169 -0
  58. package/RegionSelectorSidebarBox/index.js +254 -0
  59. package/{src/RegionSelectorSidebarBox → RegionSelectorSidebarBox}/styles.js +13 -14
  60. package/RegionShapes/index.js +294 -0
  61. package/RegionTags/index.js +144 -0
  62. package/SettingsDialog/index.js +52 -0
  63. package/SettingsProvider/index.js +60 -0
  64. package/Shortcuts/ShortcutField.js +46 -0
  65. package/Shortcuts/index.js +133 -0
  66. package/ShortcutsManager/index.js +155 -0
  67. package/Sidebar/index.js +69 -0
  68. package/SidebarBoxContainer/index.js +93 -0
  69. package/SmallToolButton/index.js +42 -0
  70. package/TagsSidebarBox/index.js +105 -0
  71. package/TaskDescriptionSidebarBox/index.js +58 -0
  72. package/Theme/index.js +30 -0
  73. package/VideoOrImageCanvasBackground/index.js +151 -0
  74. package/colors.js +14 -0
  75. package/hooks/use-colors.js +127 -0
  76. package/hooks/use-event-callback.js +10 -0
  77. package/hooks/use-exclude-pattern.js +24 -0
  78. package/hooks/use-load-image.js +26 -0
  79. package/hooks/use-window-size.js +46 -0
  80. package/{src/hooks → hooks}/xpattern.js +1 -1
  81. package/index.js +3 -0
  82. package/lib.js +3 -0
  83. package/package.json +1 -1
  84. package/stories.js +5 -0
  85. package/utils/blocks-to-article.js +60 -0
  86. package/{src/utils → utils}/blocks-to-article.test.js +5 -8
  87. package/{src/utils → utils}/default-locked-until.js +2 -1
  88. package/{src/utils → utils}/filter-only-unique.js +1 -1
  89. package/utils/get-from-local-storage.js +7 -0
  90. package/utils/get-hotkey-help-text.js +9 -0
  91. package/utils/get-landmarks-with-transform.js +40 -0
  92. package/utils/photosToImages.js +85 -0
  93. package/utils/regions-groups.js +28 -0
  94. package/utils/regions-to-blocks.js +18 -0
  95. package/utils/saveable-actions-enum.js +3 -0
  96. package/utils/set-in-local-storage.js +3 -0
  97. package/utils/sleep.js +7 -0
  98. package/utils/uuid-to-hash.js +5 -0
  99. package/.babelrc +0 -6
  100. package/.env +0 -1
  101. package/.flowconfig +0 -2
  102. package/.github/workflows/release-on-master.yml +0 -32
  103. package/.github/workflows/test.yml +0 -16
  104. package/.prettierrc +0 -3
  105. package/.releaserc.js +0 -18
  106. package/.storybook/addons.js +0 -2
  107. package/.storybook/config.js +0 -16
  108. package/LICENSE +0 -21
  109. package/public/favicon.ico +0 -0
  110. package/public/index.html +0 -38
  111. package/src/Annotator/bike-pic.png +0 -0
  112. package/src/Annotator/bike-pic2.png +0 -0
  113. package/src/Annotator/dab-keyframes.story.json +0 -1
  114. package/src/Annotator/exampleImages.js +0 -48
  115. package/src/Annotator/examplePhotos.js +0 -7603
  116. package/src/Annotator/index.js +0 -380
  117. package/src/Annotator/index.story.js +0 -877
  118. package/src/Annotator/poses.story.js +0 -150
  119. package/src/Annotator/reducers/combine-reducers.js +0 -7
  120. package/src/Annotator/reducers/convert-expanding-line-to-polygon.js +0 -53
  121. package/src/Annotator/reducers/general-reducer.js +0 -1228
  122. package/src/Annotator/reducers/get-active-image.js +0 -21
  123. package/src/Annotator/reducers/get-implied-video-regions.js +0 -115
  124. package/src/Annotator/reducers/history-handler.js +0 -60
  125. package/src/Annotator/reducers/image-reducer.js +0 -23
  126. package/src/Annotator/reducers/video-reducer.js +0 -85
  127. package/src/Annotator/video.story.js +0 -51
  128. package/src/ClassSelectionMenu/index.js +0 -112
  129. package/src/Crosshairs/index.js +0 -64
  130. package/src/DebugSidebarBox/index.js +0 -36
  131. package/src/DemoSite/Editor.js +0 -235
  132. package/src/DemoSite/ErrorBoundaryDialog.js +0 -34
  133. package/src/DemoSite/index.js +0 -41
  134. package/src/DemoSite/index.story.js +0 -10
  135. package/src/DemoSite/simple-segmentation-example.json +0 -572
  136. package/src/Editor/annotation-plugin/annotation.js +0 -536
  137. package/src/Editor/index.js +0 -50
  138. package/src/Editor/readOnly.js +0 -21
  139. package/src/Errorer/index.js +0 -13
  140. package/src/FullImageSegmentationAnnotator/hard1.story.jpg +0 -0
  141. package/src/FullImageSegmentationAnnotator/hard2.story.jpg +0 -0
  142. package/src/FullImageSegmentationAnnotator/hard3.story.jpg +0 -0
  143. package/src/FullImageSegmentationAnnotator/index.js +0 -7
  144. package/src/FullImageSegmentationAnnotator/index.story.js +0 -177
  145. package/src/FullImageSegmentationAnnotator/orange.story.png +0 -0
  146. package/src/GroupSelectorSidebarBox/index.js +0 -48
  147. package/src/GroupsEditorSidebarBox/index.js +0 -108
  148. package/src/HelpSidebarBox/index.js +0 -43
  149. package/src/HighlightBox/index.js +0 -143
  150. package/src/HistorySidebarBox/index.js +0 -78
  151. package/src/ImageCanvas/dancing-man.story.jpg +0 -0
  152. package/src/ImageCanvas/index.js +0 -515
  153. package/src/ImageCanvas/index.story.js +0 -314
  154. package/src/ImageCanvas/mouse_mask.story.png +0 -0
  155. package/src/ImageCanvas/region-tools.js +0 -171
  156. package/src/ImageCanvas/seves_desk.story.jpg +0 -0
  157. package/src/ImageCanvas/use-mouse.js +0 -168
  158. package/src/ImageCanvas/use-project-box.js +0 -23
  159. package/src/ImageCanvas/use-wasd-mode.js +0 -50
  160. package/src/ImageMask/index.js +0 -127
  161. package/src/ImageMask/load-image.js +0 -32
  162. package/src/ImageSelectorSidebarBox/index.js +0 -54
  163. package/src/KeyframeTimeline/get-time-string.js +0 -25
  164. package/src/KeyframeTimeline/index.js +0 -223
  165. package/src/KeyframesSelectorSidebarBox/index.js +0 -93
  166. package/src/LandingPage/content.md +0 -57
  167. package/src/LandingPage/github-markdown.css +0 -964
  168. package/src/LandingPage/index.js +0 -147
  169. package/src/Locker/index.js +0 -13
  170. package/src/MainLayout/RightSidebarItemsWrapper.js +0 -21
  171. package/src/MainLayout/icon-dictionary.js +0 -79
  172. package/src/MainLayout/index.js +0 -564
  173. package/src/MainLayout/index.story.js +0 -240
  174. package/src/MainLayout/types.js +0 -171
  175. package/src/MainLayout/use-implied-video-regions.js +0 -17
  176. package/src/MetadataEditorSidebarBox/index.js +0 -160
  177. package/src/PageSelector/index.js +0 -159
  178. package/src/PointDistances/index.js +0 -90
  179. package/src/PreventScrollToParents/index.js +0 -48
  180. package/src/PreventScrollToParents/index.story.js +0 -23
  181. package/src/RegionLabel/index.js +0 -236
  182. package/src/RegionSelectAndTransformBoxes/index.js +0 -236
  183. package/src/RegionSelectorSidebarBox/index.js +0 -220
  184. package/src/RegionShapes/index.js +0 -254
  185. package/src/RegionTags/index.js +0 -136
  186. package/src/SettingsDialog/index.js +0 -58
  187. package/src/SettingsProvider/index.js +0 -57
  188. package/src/Shortcuts/ShortcutField.js +0 -44
  189. package/src/Shortcuts/index.js +0 -129
  190. package/src/ShortcutsManager/index.js +0 -162
  191. package/src/Sidebar/index.js +0 -117
  192. package/src/SidebarBoxContainer/index.js +0 -93
  193. package/src/SmallToolButton/index.js +0 -57
  194. package/src/TagsSidebarBox/index.js +0 -93
  195. package/src/TaskDescriptionSidebarBox/index.js +0 -43
  196. package/src/Theme/index.js +0 -36
  197. package/src/VideoOrImageCanvasBackground/index.js +0 -170
  198. package/src/colors.js +0 -32
  199. package/src/hooks/use-colors.js +0 -75
  200. package/src/hooks/use-event-callback.js +0 -11
  201. package/src/hooks/use-exclude-pattern.js +0 -27
  202. package/src/hooks/use-load-image.js +0 -21
  203. package/src/hooks/use-window-size.js +0 -46
  204. package/src/hooks/xpattern.png +0 -0
  205. package/src/index.js +0 -18
  206. package/src/lib.js +0 -7
  207. package/src/screenshot.png +0 -0
  208. package/src/site.css +0 -5
  209. package/src/stories.js +0 -2
  210. package/src/utils/blocks-to-article.js +0 -61
  211. package/src/utils/get-from-local-storage.js +0 -7
  212. package/src/utils/get-hotkey-help-text.js +0 -11
  213. package/src/utils/get-landmarks-with-transform.js +0 -23
  214. package/src/utils/photosToImages.js +0 -67
  215. package/src/utils/regions-groups.js +0 -19
  216. package/src/utils/regions-to-blocks.js +0 -16
  217. package/src/utils/saveable-actions-enum.js +0 -5
  218. package/src/utils/set-in-local-storage.js +0 -6
  219. package/src/utils/sleep.js +0 -3
  220. package/src/utils/uuid-to-hash.js +0 -5
  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
- )