@searpent/react-image-annotate 2.0.75 → 2.0.77

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