@abidibo/react-cam-roi 0.0.8 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +340 -39
- package/dist/Components/BoolField/BoolField.module.css +60 -0
- package/dist/Components/BoolField/index.d.ts +5 -0
- package/dist/Components/BoolField/index.js +13 -0
- package/dist/Components/Button/Button.module.css +27 -0
- package/dist/Components/Button/index.d.ts +8 -0
- package/dist/Components/Button/index.js +15 -0
- package/dist/Components/EnumField/EnumField.module.css +61 -0
- package/dist/Components/EnumField/index.d.ts +10 -0
- package/dist/Components/EnumField/index.js +16 -0
- package/dist/Components/IconButton/IconButton.module.css +8 -3
- package/dist/Components/IconButton/index.d.ts +1 -0
- package/dist/Components/IconButton/index.js +3 -3
- package/dist/Components/Modal/Modal.module.css +7 -0
- package/dist/Components/Modal/index.d.ts +2 -1
- package/dist/Components/Modal/index.js +3 -3
- package/dist/Components/NumberField/NumberField.module.css +60 -0
- package/dist/Components/NumberField/index.d.ts +3 -0
- package/dist/Components/NumberField/index.js +13 -0
- package/dist/Components/RoiEditor/Canvas.d.ts +2 -0
- package/dist/Components/RoiEditor/Canvas.js +20 -8
- package/dist/Components/RoiEditor/Hooks.d.ts +13 -0
- package/dist/Components/RoiEditor/Hooks.js +84 -5
- package/dist/Components/RoiEditor/ParameterField.d.ts +9 -0
- package/dist/Components/RoiEditor/ParameterField.js +27 -0
- package/dist/Components/RoiEditor/ParametersModalForm/ParametersModalForm.module.css +5 -0
- package/dist/Components/RoiEditor/ParametersModalForm/index.d.ts +10 -0
- package/dist/Components/RoiEditor/ParametersModalForm/index.js +31 -0
- package/dist/Components/RoiEditor/ShapesList.js +19 -6
- package/dist/Components/RoiEditor/Toolbar.js +13 -3
- package/dist/Components/RoiEditor/Toolbar.module.css +13 -1
- package/dist/Components/RoiEditor/Types.d.ts +52 -2
- package/dist/Components/RoiEditor/Utils.d.ts +18 -1
- package/dist/Components/RoiEditor/Utils.js +106 -0
- package/dist/Components/RoiEditor/index.d.ts +4 -1
- package/dist/Components/RoiEditor/index.js +44 -6
- package/dist/Components/TextField/TextField.module.css +61 -0
- package/dist/Components/TextField/index.d.ts +6 -0
- package/dist/Components/TextField/index.js +13 -0
- package/dist/Components/Typography/index.d.ts +1 -0
- package/dist/Components/Typography/index.js +2 -2
- package/dist/Icons/SaveIcon.d.ts +6 -0
- package/dist/Icons/SaveIcon.js +5 -0
- package/dist/Providers/EditorProvider.d.ts +12 -2
- package/dist/Providers/EditorProvider.js +17 -2
- package/dist/Providers/UiProvider.d.ts +24 -1
- package/dist/Providers/UiProvider.js +30 -1
- package/dist/Types.d.ts +10 -0
- package/dist/Types.js +1 -0
- package/dist/Utils/index.d.ts +1 -1
- package/dist/Utils/index.js +1 -1
- package/package.json +7 -2
- package/dist/Components/RoiEditor/ParametersModalForm.d.ts +0 -5
- package/dist/Components/RoiEditor/ParametersModalForm.js +0 -8
@@ -1,3 +1,15 @@
|
|
1
|
+
.toolbar-info {
|
2
|
+
padding: .5rem;
|
3
|
+
}
|
4
|
+
.toolbar-info-light {
|
5
|
+
background-color: #ddd;;
|
6
|
+
color: #000;
|
7
|
+
}
|
8
|
+
.toolbar-info-dark {
|
9
|
+
background-color: #222;
|
10
|
+
color: #fff;
|
11
|
+
}
|
12
|
+
|
1
13
|
.toolbar {
|
2
14
|
align-items: center;
|
3
15
|
display: flex;
|
@@ -28,7 +40,7 @@
|
|
28
40
|
|
29
41
|
.toolbar-spacer {
|
30
42
|
height: 20px;
|
31
|
-
margin: 0 .5rem
|
43
|
+
margin: 0 .5rem;
|
32
44
|
width: 1px;
|
33
45
|
}
|
34
46
|
|
@@ -38,11 +38,12 @@ export type ConfigurationParameter = {
|
|
38
38
|
unit: string;
|
39
39
|
type: DataTypeEnum;
|
40
40
|
options: {
|
41
|
-
value: number | string
|
41
|
+
value: number | string;
|
42
42
|
label: string;
|
43
43
|
}[];
|
44
|
+
multiple?: boolean;
|
44
45
|
required: boolean;
|
45
|
-
value: number | string | boolean | null;
|
46
|
+
value: number | string | boolean | string[] | number[] | null;
|
46
47
|
};
|
47
48
|
export type RoiConfiguration = {
|
48
49
|
role: string;
|
@@ -56,6 +57,10 @@ export type RoiConfiguration = {
|
|
56
57
|
export type Configuration = {
|
57
58
|
parameters: ConfigurationParameter[];
|
58
59
|
rois: RoiConfiguration[];
|
60
|
+
options?: {
|
61
|
+
hideForbiddenTools?: boolean;
|
62
|
+
description?: string;
|
63
|
+
};
|
59
64
|
};
|
60
65
|
export interface INotify {
|
61
66
|
info: (message: string) => void;
|
@@ -63,3 +68,48 @@ export interface INotify {
|
|
63
68
|
error: (message: string) => void;
|
64
69
|
success: (message: string) => void;
|
65
70
|
}
|
71
|
+
export type Metadata = {
|
72
|
+
parameters: OutputParameter[];
|
73
|
+
rois: {
|
74
|
+
id: string;
|
75
|
+
parameters: OutputParameter[];
|
76
|
+
}[];
|
77
|
+
};
|
78
|
+
export type OutputShapeRect = {
|
79
|
+
top: number;
|
80
|
+
left: number;
|
81
|
+
width: number;
|
82
|
+
height: number;
|
83
|
+
color: string;
|
84
|
+
};
|
85
|
+
export type OutputShapePolyline = {
|
86
|
+
points: {
|
87
|
+
x: number;
|
88
|
+
y: number;
|
89
|
+
}[];
|
90
|
+
top: number;
|
91
|
+
left: number;
|
92
|
+
color: string;
|
93
|
+
};
|
94
|
+
export type OutputShapePolygon = {
|
95
|
+
points: {
|
96
|
+
x: number;
|
97
|
+
y: number;
|
98
|
+
}[];
|
99
|
+
top: number;
|
100
|
+
left: number;
|
101
|
+
color: string;
|
102
|
+
};
|
103
|
+
export interface OutputParameter {
|
104
|
+
codename: string;
|
105
|
+
value: number | string | boolean | string[] | number[] | null;
|
106
|
+
}
|
107
|
+
export interface OutputRoi {
|
108
|
+
parameters: OutputParameter[];
|
109
|
+
type: ShapeType;
|
110
|
+
shape: OutputShapeRect | OutputShapePolyline | OutputShapePolygon;
|
111
|
+
}
|
112
|
+
export interface Output {
|
113
|
+
parameters: OutputParameter[];
|
114
|
+
rois: OutputRoi[];
|
115
|
+
}
|
@@ -1,5 +1,22 @@
|
|
1
|
-
import { Configuration, INotify, Shapes, ToolEnum } from './Types';
|
1
|
+
import { Configuration, ConfigurationParameter, INotify, Metadata, Shape, Shapes, ShapeType, ToolEnum } from './Types';
|
2
2
|
export declare const notify: INotify;
|
3
3
|
export declare const enableRois: (configuration: Configuration) => boolean;
|
4
4
|
export declare const enableMainMetadata: (configuration: Configuration) => boolean;
|
5
5
|
export declare const canDrawShape: (configuration: Configuration, shapeType: Omit<ToolEnum, ToolEnum.Pointer>, shapes: Shapes, notify: INotify, message: string) => boolean;
|
6
|
+
export declare const validateParametersForm: (parameters: ConfigurationParameter[], fields: Record<string, unknown>, setErrors: (errors: Record<string, string>) => void) => boolean;
|
7
|
+
export declare const validate: (configuration: Configuration, shapes: Shapes, metadata: Metadata, strings: Record<string, string>) => [boolean, string[]];
|
8
|
+
export declare const fabricShapeToOutputShape: (shape: Shape, type: ShapeType) => {
|
9
|
+
top: number;
|
10
|
+
left: number;
|
11
|
+
width: number;
|
12
|
+
height: number;
|
13
|
+
color: string;
|
14
|
+
points?: undefined;
|
15
|
+
} | {
|
16
|
+
points: any;
|
17
|
+
top: number;
|
18
|
+
left: number;
|
19
|
+
color: string;
|
20
|
+
width?: undefined;
|
21
|
+
height?: undefined;
|
22
|
+
};
|
@@ -35,3 +35,109 @@ export const canDrawShape = (configuration, shapeType, shapes, notify, message)
|
|
35
35
|
}
|
36
36
|
return res;
|
37
37
|
};
|
38
|
+
export const validateParametersForm = (parameters, fields, setErrors) => {
|
39
|
+
const err = {};
|
40
|
+
parameters.forEach((p) => {
|
41
|
+
if (p.required && isEmpty(fields[p.codename])) {
|
42
|
+
err[p.codename] = 'requiredField';
|
43
|
+
}
|
44
|
+
});
|
45
|
+
if (Object.keys(err).length > 0) {
|
46
|
+
setErrors(err);
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
return true;
|
50
|
+
};
|
51
|
+
const isEmpty = (v) => {
|
52
|
+
if (typeof v === 'string') {
|
53
|
+
return v.length === 0;
|
54
|
+
}
|
55
|
+
if (Array.isArray(v)) {
|
56
|
+
return v.length === 0;
|
57
|
+
}
|
58
|
+
return v === null || v === undefined;
|
59
|
+
};
|
60
|
+
export const validate = (configuration, shapes, metadata, strings) => {
|
61
|
+
const errors = [];
|
62
|
+
// check main parameters
|
63
|
+
if (configuration.parameters.length) {
|
64
|
+
if (metadata.parameters.find((p) => { var _a; return ((_a = configuration.parameters.find((p2) => p2.codename === p.codename)) === null || _a === void 0 ? void 0 : _a.required) && isEmpty(p.value); })) {
|
65
|
+
errors.push(strings.missingRequiredValuesInMainParameters);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
// check rois number
|
69
|
+
configuration.rois.forEach((roi) => {
|
70
|
+
// check multiplicity
|
71
|
+
if (roi.multiplicity) {
|
72
|
+
switch (roi.multiplicity.operator) {
|
73
|
+
case OperatorEnum.Eq:
|
74
|
+
if (Object.values(shapes).filter((s) => s.type === roi.type).length !== roi.multiplicity.threshold) {
|
75
|
+
errors.push(strings.shapesOfTypeShouldBeEqualToThreshold
|
76
|
+
.replace('{type}', String(roi.type))
|
77
|
+
.replace('{threshold}', roi.multiplicity.threshold.toString()));
|
78
|
+
}
|
79
|
+
break;
|
80
|
+
case OperatorEnum.Lt:
|
81
|
+
if (Object.values(shapes).filter((s) => s.type === roi.type).length >= roi.multiplicity.threshold) {
|
82
|
+
errors.push(strings.shapesOfTypeShouldBeLessThanThreshold
|
83
|
+
.replace('{type}', String(roi.type))
|
84
|
+
.replace('{threshold}', roi.multiplicity.threshold.toString()));
|
85
|
+
}
|
86
|
+
break;
|
87
|
+
case OperatorEnum.Lte:
|
88
|
+
if (Object.values(shapes).filter((s) => s.type === roi.type).length > roi.multiplicity.threshold) {
|
89
|
+
errors.push(strings.shapesOfTypeShouldBeLessThanOrEqualToThreshold
|
90
|
+
.replace('{type}', String(roi.type))
|
91
|
+
.replace('{threshold}', roi.multiplicity.threshold.toString()));
|
92
|
+
}
|
93
|
+
break;
|
94
|
+
case OperatorEnum.Gt:
|
95
|
+
if (Object.values(shapes).filter((s) => s.type === roi.type).length <= roi.multiplicity.threshold) {
|
96
|
+
errors.push(strings.shapesOfTypeShouldBeGreaterThanThreshold
|
97
|
+
.replace('{type}', String(roi.type))
|
98
|
+
.replace('{threshold}', roi.multiplicity.threshold.toString()));
|
99
|
+
}
|
100
|
+
break;
|
101
|
+
case OperatorEnum.Gte:
|
102
|
+
if (Object.values(shapes).filter((s) => s.type === roi.type).length < roi.multiplicity.threshold) {
|
103
|
+
errors.push(strings.shapesOfTypeShouldBeGreaterThanOrEqualToThreshold
|
104
|
+
.replace('{type}', String(roi.type))
|
105
|
+
.replace('{threshold}', roi.multiplicity.threshold.toString()));
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
});
|
110
|
+
// check rois metadata
|
111
|
+
Object.keys(shapes).forEach(shapeId => {
|
112
|
+
var _a, _b;
|
113
|
+
const type = shapes[shapeId].type;
|
114
|
+
const confParameters = (_b = (_a = configuration.rois.find((r) => r.type === type)) === null || _a === void 0 ? void 0 : _a.parameters) !== null && _b !== void 0 ? _b : [];
|
115
|
+
confParameters.forEach((p) => {
|
116
|
+
var _a, _b;
|
117
|
+
if (p.required && isEmpty((_b = (_a = metadata.rois.find((r) => r.id === shapeId)) === null || _a === void 0 ? void 0 : _a.parameters.find((p) => p.codename === p.codename)) === null || _b === void 0 ? void 0 : _b.value)) {
|
118
|
+
errors.push(strings.missingRequiredValuesInShapeParameters.replace('{id}', shapeId));
|
119
|
+
}
|
120
|
+
});
|
121
|
+
});
|
122
|
+
return [errors.length === 0, errors];
|
123
|
+
};
|
124
|
+
export const fabricShapeToOutputShape = (shape, type) => {
|
125
|
+
switch (type) {
|
126
|
+
case "rect" /* ToolEnum.Rectangle */:
|
127
|
+
return {
|
128
|
+
top: shape.top,
|
129
|
+
left: shape.left,
|
130
|
+
width: shape.width,
|
131
|
+
height: shape.height,
|
132
|
+
color: shape.stroke
|
133
|
+
};
|
134
|
+
case "polygon" /* ToolEnum.Polygon */:
|
135
|
+
case "polyline" /* ToolEnum.Polyline */:
|
136
|
+
return {
|
137
|
+
points: shape.get('points'),
|
138
|
+
top: shape.top,
|
139
|
+
left: shape.left,
|
140
|
+
color: shape.stroke
|
141
|
+
};
|
142
|
+
}
|
143
|
+
};
|
@@ -1,7 +1,10 @@
|
|
1
|
-
import { Configuration } from './Types';
|
1
|
+
import { Configuration, Output } from './Types';
|
2
2
|
export type RoiEditorProps = {
|
3
3
|
imageUrl: string;
|
4
4
|
configuration: Configuration;
|
5
|
+
onSubmit: (data: Output) => void;
|
6
|
+
initialData?: Output;
|
7
|
+
id: string;
|
5
8
|
};
|
6
9
|
declare const RoiEditor: React.FC<RoiEditorProps>;
|
7
10
|
export default RoiEditor;
|
@@ -6,31 +6,69 @@ import { css, log } from '../../Utils';
|
|
6
6
|
import { Loader } from '../Loader';
|
7
7
|
import Canvas from './Canvas';
|
8
8
|
import { useCanvasSize } from './Hooks';
|
9
|
-
import ShapesList from './ShapesList';
|
10
9
|
import styles from './RoiEditor.module.css';
|
10
|
+
import ShapesList from './ShapesList';
|
11
11
|
import Toolbar from './Toolbar';
|
12
|
+
import { fabricShapeToOutputShape, validate } from './Utils';
|
12
13
|
// https://github.com/n-mazaheri/image-editor
|
13
|
-
const RoiEditor = ({ imageUrl, configuration }) => {
|
14
|
-
|
14
|
+
const RoiEditor = ({ imageUrl, configuration, onSubmit, initialData, id }) => {
|
15
|
+
var _a, _b, _c;
|
16
|
+
const { themeMode, enableLogs, pickerColors, strings, notify } = useContext(UiContext);
|
15
17
|
const { imageSize, canvasSize, wrapperRef, isReady } = useCanvasSize(imageUrl);
|
16
18
|
const [activeTool, setActiveTool] = useState("pointer" /* ToolEnum.Pointer */);
|
17
19
|
const [activeColor, setActiveColor] = useState(pickerColors[0]);
|
20
|
+
const [metadata, setMetadata] = useState({
|
21
|
+
parameters: [
|
22
|
+
...((_a = configuration.parameters.map((p) => {
|
23
|
+
const initial = initialData === null || initialData === void 0 ? void 0 : initialData.parameters.find((p) => p.codename === p.codename);
|
24
|
+
return {
|
25
|
+
codename: p.codename,
|
26
|
+
value: initial ? initial.value : p.value,
|
27
|
+
};
|
28
|
+
})) !== null && _a !== void 0 ? _a : []),
|
29
|
+
],
|
30
|
+
rois: [],
|
31
|
+
});
|
18
32
|
const [shapes, setShapes] = useState({});
|
19
33
|
const addShape = useCallback((id, type, shape) => setShapes(Object.assign(Object.assign({}, shapes), { [id]: { type, shape } })), [shapes]);
|
34
|
+
const addShapes = useCallback((s) => setShapes(Object.assign(Object.assign({}, shapes), s.reduce((r, s) => (Object.assign(Object.assign({}, r), { [s.id]: s })), {}))), [shapes]);
|
20
35
|
const removeShape = useCallback((id) => {
|
21
36
|
const newShapes = Object.assign({}, shapes);
|
22
37
|
delete newShapes[id];
|
23
38
|
setShapes(newShapes);
|
24
|
-
|
39
|
+
setMetadata(Object.assign(Object.assign({}, metadata), { rois: metadata.rois.filter((r) => r.id !== id) }));
|
40
|
+
}, [shapes, metadata]);
|
41
|
+
const handleSubmit = useCallback(() => {
|
42
|
+
var _a, _b;
|
43
|
+
const [isValid, errors] = validate(configuration, shapes, metadata, strings);
|
44
|
+
if (isValid) {
|
45
|
+
onSubmit({
|
46
|
+
parameters: (_b = (_a = metadata.parameters) === null || _a === void 0 ? void 0 : _a.map((p) => ({ codename: p.codename, value: p.value }))) !== null && _b !== void 0 ? _b : [],
|
47
|
+
rois: Object.keys(shapes).map((shapeId) => {
|
48
|
+
var _a, _b, _c;
|
49
|
+
return ({
|
50
|
+
parameters: (_c = (_b = (_a = metadata.rois
|
51
|
+
.find((r) => r.id === shapeId)) === null || _a === void 0 ? void 0 : _a.parameters) === null || _b === void 0 ? void 0 : _b.map((p) => ({ codename: p.codename, value: p.value }))) !== null && _c !== void 0 ? _c : [],
|
52
|
+
type: shapes[shapeId].type,
|
53
|
+
shape: fabricShapeToOutputShape(shapes[shapeId].shape, shapes[shapeId].shape.type),
|
54
|
+
});
|
55
|
+
}),
|
56
|
+
});
|
57
|
+
}
|
58
|
+
else {
|
59
|
+
notify.error(strings.invalidSubmission + '\n' + errors.map((e) => `- ${e}`).join('\n'));
|
60
|
+
}
|
61
|
+
}, [onSubmit, configuration, shapes, metadata, strings, notify]);
|
25
62
|
log('info', enableLogs, 'react-cam-roi', 'active tool', activeTool);
|
26
63
|
log('info', enableLogs, 'react-cam-roi', 'canvas size', canvasSize);
|
64
|
+
log('info', enableLogs, 'react-cam-roi', 'metadata', metadata);
|
27
65
|
if (!isReady) {
|
28
66
|
return _jsx(Loader, {});
|
29
67
|
}
|
30
|
-
return (_jsx(EditorProvider, { activeTool: activeTool, setActiveTool: setActiveTool, activeColor: activeColor, setActiveColor: setActiveColor, shapes: shapes, addShape: addShape, removeShape: removeShape, configuration: configuration, children: _jsxs("div", { style: { maxWidth: '100%', width: `${imageSize.width}px` }, ref: wrapperRef, children: [_jsx(Toolbar, {}), _jsx("div", { className: css('canvasWrapper', styles, themeMode), style: {
|
68
|
+
return (_jsx(EditorProvider, { id: id, hideForbiddenTools: (_c = (_b = configuration.options) === null || _b === void 0 ? void 0 : _b.hideForbiddenTools) !== null && _c !== void 0 ? _c : false, activeTool: activeTool, setActiveTool: setActiveTool, activeColor: activeColor, setActiveColor: setActiveColor, shapes: shapes, addShape: addShape, addShapes: addShapes, removeShape: removeShape, configuration: configuration, metadata: metadata, setMetadata: setMetadata, onSubmit: handleSubmit, children: _jsxs("div", { style: { maxWidth: '100%', width: `${imageSize.width}px` }, ref: wrapperRef, children: [_jsx(Toolbar, {}), _jsx("div", { className: css('canvasWrapper', styles, themeMode), style: {
|
31
69
|
width: `${canvasSize.width}px`,
|
32
70
|
height: `${canvasSize.height}px`,
|
33
71
|
backgroundImage: `url(${imageUrl})`,
|
34
|
-
}, children: _jsx(Canvas, { canvasSize: canvasSize }) }), _jsx(ShapesList, {})] }) }));
|
72
|
+
}, children: _jsx(Canvas, { canvasSize: canvasSize, initialData: initialData }) }), _jsx(ShapesList, {})] }) }));
|
35
73
|
};
|
36
74
|
export default RoiEditor;
|
@@ -0,0 +1,61 @@
|
|
1
|
+
/*
|
2
|
+
.text-field-wrapper {
|
3
|
+
margin-bottom: 2rem;
|
4
|
+
}
|
5
|
+
.text-field-wrapper-light {
|
6
|
+
}
|
7
|
+
.text-field-wrapper-dark {
|
8
|
+
}
|
9
|
+
*/
|
10
|
+
|
11
|
+
.text-field {
|
12
|
+
border-radius: 0.25rem;
|
13
|
+
box-sizing: border-box;
|
14
|
+
padding: 0.5rem;
|
15
|
+
width: 100%;
|
16
|
+
}
|
17
|
+
.text-field:focus-visible {
|
18
|
+
outline: none;
|
19
|
+
border: 1px solid #1976d2;
|
20
|
+
}
|
21
|
+
.text-field-light {
|
22
|
+
background-color: #fff;
|
23
|
+
color: #333;
|
24
|
+
border: 1px solid #ccc;
|
25
|
+
}
|
26
|
+
.text-field-dark {
|
27
|
+
background-color: #333;
|
28
|
+
border: 1px solid #666;
|
29
|
+
color: #fff;
|
30
|
+
}
|
31
|
+
.text-field-error {
|
32
|
+
border: 1px solid #d32f2f;
|
33
|
+
}
|
34
|
+
.text-field-label {
|
35
|
+
font-weight: bold;
|
36
|
+
display: block;
|
37
|
+
margin: 0 0 1rem 0;
|
38
|
+
}
|
39
|
+
/*
|
40
|
+
.text-fiel-label-light {
|
41
|
+
}
|
42
|
+
.text-field-label-dark {
|
43
|
+
}
|
44
|
+
*/
|
45
|
+
.text-field-label-error {
|
46
|
+
color: #d32f2f;
|
47
|
+
}
|
48
|
+
.text-field-helper-text {
|
49
|
+
font-style: italic;
|
50
|
+
font-size: 0.9rem;
|
51
|
+
margin-top: 0.5rem;
|
52
|
+
}
|
53
|
+
/*
|
54
|
+
.text-field-helper-text-light {
|
55
|
+
}
|
56
|
+
.text-field-helper-text-dark {
|
57
|
+
}
|
58
|
+
*/
|
59
|
+
.text-field-helper-text-error {
|
60
|
+
color: #d32f2f;
|
61
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
import { useContext } from 'react';
|
3
|
+
import { UiContext } from '../../Providers/UiProvider';
|
4
|
+
import { css } from '../../Utils';
|
5
|
+
import styles from './TextField.module.css';
|
6
|
+
const TextField = ({ onChange, type = 'text', value, label, helperText, error, required = false, readOnly = false, disabled = false, }) => {
|
7
|
+
const { themeMode, Typography } = useContext(UiContext);
|
8
|
+
const handleChange = (e) => {
|
9
|
+
onChange(e.target.value);
|
10
|
+
};
|
11
|
+
return (_jsxs("div", { className: css('text-field-wrapper', styles, themeMode), children: [_jsx("label", { className: `${css('text-field-label', styles, themeMode)} ${error ? css('text-field-label-error', styles, null) : ''}`, children: _jsxs(Typography, { children: [label, required && ' *'] }) }), _jsx("input", { type: type, className: `${css('text-field', styles, themeMode)} ${error ? css('text-field-error', styles, null) : ''}`, onChange: handleChange, value: value, readOnly: readOnly, disabled: disabled }), helperText && (_jsx(Typography, { component: 'div', className: `${css('text-field-helper-text', styles, themeMode)} ${error ? css('text-field-helper-text-error', styles, null) : ''}`, children: helperText }))] }));
|
12
|
+
};
|
13
|
+
export default TextField;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
const Typography = ({ children, className = '', component = 'span' }) => {
|
2
|
+
const Typography = ({ children, style = {}, className = '', component = 'span' }) => {
|
3
3
|
const Tag = component;
|
4
|
-
return _jsx(Tag, { className: className, children: children });
|
4
|
+
return _jsx(Tag, { className: className, style: style, children: children });
|
5
5
|
};
|
6
6
|
export default Typography;
|
@@ -0,0 +1,5 @@
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
+
const SaveIcon = ({ color = 'black', style = {} }) => {
|
3
|
+
return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 -960 960 960", width: "24px", style: style, children: _jsx("path", { fill: color, d: "M840-680v480q0 33-23.5 56.5T760-120H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h480l160 160Zm-80 34L646-760H200v560h560v-446ZM480-240q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35ZM240-560h360v-160H240v160Zm-40-86v446-560 114Z" }) }));
|
4
|
+
};
|
5
|
+
export default SaveIcon;
|
@@ -1,16 +1,26 @@
|
|
1
1
|
import { PropsWithChildren } from 'react';
|
2
|
-
import { Configuration, Shape, Shapes, ShapeType, ToolEnum } from '../Components/RoiEditor/Types';
|
2
|
+
import { Configuration, Metadata, Shape, Shapes, ShapeType, ToolEnum } from '../Components/RoiEditor/Types';
|
3
3
|
type EditorContextType = {
|
4
|
+
hideForbiddenTools: boolean;
|
4
5
|
activeTool: ToolEnum;
|
5
6
|
setActiveTool: (tool: ToolEnum) => void;
|
6
7
|
activeColor: string;
|
7
8
|
setActiveColor: (color: string) => void;
|
8
9
|
shapes: Shapes;
|
9
10
|
addShape: (id: string, type: ShapeType, shape: Shape) => void;
|
11
|
+
addShapes: (shapes: {
|
12
|
+
id: string;
|
13
|
+
type: ShapeType;
|
14
|
+
shape: Shape;
|
15
|
+
}[]) => void;
|
10
16
|
removeShape: (id: string) => void;
|
11
17
|
configuration: Configuration;
|
18
|
+
metadata: Metadata;
|
19
|
+
setMetadata: (data: Metadata) => void;
|
20
|
+
onSubmit: () => void;
|
21
|
+
id: string;
|
12
22
|
};
|
13
23
|
export declare const EditorContext: import("react").Context<EditorContextType | undefined>;
|
14
24
|
export declare function useEditorContext(): EditorContextType;
|
15
|
-
declare const EditorProvider: ({ children, activeTool, setActiveTool, activeColor, setActiveColor, shapes, addShape, removeShape, configuration, }: PropsWithChildren<EditorContextType>) => import("react/jsx-runtime").JSX.Element;
|
25
|
+
declare const EditorProvider: ({ children, id, hideForbiddenTools, activeTool, setActiveTool, activeColor, setActiveColor, shapes, addShape, addShapes, removeShape, configuration, metadata, setMetadata, onSubmit, }: PropsWithChildren<EditorContextType>) => import("react/jsx-runtime").JSX.Element;
|
16
26
|
export default EditorProvider;
|
@@ -8,7 +8,22 @@ export function useEditorContext() {
|
|
8
8
|
}
|
9
9
|
return context;
|
10
10
|
}
|
11
|
-
const EditorProvider = ({ children, activeTool, setActiveTool, activeColor, setActiveColor, shapes, addShape, removeShape, configuration, }) => {
|
12
|
-
return (_jsx(EditorContext.Provider, { value: {
|
11
|
+
const EditorProvider = ({ children, id, hideForbiddenTools, activeTool, setActiveTool, activeColor, setActiveColor, shapes, addShape, addShapes, removeShape, configuration, metadata, setMetadata, onSubmit, }) => {
|
12
|
+
return (_jsx(EditorContext.Provider, { value: {
|
13
|
+
id,
|
14
|
+
hideForbiddenTools,
|
15
|
+
activeTool,
|
16
|
+
setActiveTool,
|
17
|
+
activeColor,
|
18
|
+
setActiveColor,
|
19
|
+
shapes,
|
20
|
+
addShape,
|
21
|
+
addShapes,
|
22
|
+
removeShape,
|
23
|
+
configuration,
|
24
|
+
metadata,
|
25
|
+
setMetadata,
|
26
|
+
onSubmit,
|
27
|
+
}, children: children }));
|
13
28
|
};
|
14
29
|
export default EditorProvider;
|
@@ -9,6 +9,12 @@ import CopyIcon from '../Icons/CopyIcon';
|
|
9
9
|
import AnnotateIcon from '../Icons/AnnotateIcon';
|
10
10
|
import Modal from '../Components/Modal';
|
11
11
|
import CloseIcon from '../Icons/CloseIcon';
|
12
|
+
import TextField from '../Components/TextField';
|
13
|
+
import NumberField from '../Components/NumberField';
|
14
|
+
import BoolField from '../Components/BoolField';
|
15
|
+
import EnumField from '../Components/EnumField';
|
16
|
+
import Button from '../Components/Button';
|
17
|
+
import SaveIcon from '../Icons/SaveIcon';
|
12
18
|
type UiContextType = {
|
13
19
|
children?: React.ReactNode;
|
14
20
|
enableLogs: boolean;
|
@@ -22,15 +28,25 @@ type UiContextType = {
|
|
22
28
|
SelectIcon: typeof SelectIcon;
|
23
29
|
CopyIcon: typeof CopyIcon;
|
24
30
|
AnnotateIcon: typeof AnnotateIcon;
|
31
|
+
SaveIcon: typeof SaveIcon;
|
25
32
|
CloseIcon: typeof CloseIcon;
|
33
|
+
TextField: typeof TextField;
|
34
|
+
NumberField: typeof NumberField;
|
35
|
+
BoolField: typeof BoolField;
|
36
|
+
EnumField: typeof EnumField;
|
37
|
+
Button: typeof Button;
|
26
38
|
pickerColors: string[];
|
27
39
|
notify: INotify;
|
28
40
|
strings: {
|
41
|
+
cancel: string;
|
29
42
|
cannotDrawMorePolygons: string;
|
30
43
|
cannotDrawMorePolylines: string;
|
31
44
|
cannotDrawMoreRectangles: string;
|
32
45
|
id: string;
|
46
|
+
invalidSubmission: string;
|
33
47
|
mainParametersMetadata: string;
|
48
|
+
missingRequiredValuesInMainParameters: string;
|
49
|
+
missingRequiredValuesInShapeParameters: string;
|
34
50
|
polygon: string;
|
35
51
|
polygonHelpText: string;
|
36
52
|
polyline: string;
|
@@ -39,12 +55,19 @@ type UiContextType = {
|
|
39
55
|
rectHelpText: string;
|
40
56
|
pointer: string;
|
41
57
|
pointerHelpText: string;
|
58
|
+
requiredField: string;
|
59
|
+
save: string;
|
60
|
+
shapesOfTypeShouldBeEqualToThreshold: string;
|
61
|
+
shapesOfTypeShouldBeGreaterThanThreshold: string;
|
62
|
+
shapesOfTypeShouldBeGreaterThanOrEqualToThreshold: string;
|
63
|
+
shapesOfTypeShouldBeLessThanThreshold: string;
|
64
|
+
shapesOfTypeShouldBeLessThanOrEqualToThreshold: string;
|
42
65
|
type: string;
|
43
66
|
};
|
44
67
|
};
|
45
68
|
export declare const DefaultUiContext: UiContextType;
|
46
69
|
export declare const UiContext: import("react").Context<UiContextType>;
|
47
|
-
declare const UiProvider: ({ children, enableLogs, themeMode, primaryColor, Typography, Modal, IconButton, DeleteIcon, EditIcon, SelectIcon, CopyIcon, AnnotateIcon, CloseIcon, pickerColors, notify, strings, }: PropsWithChildren<Partial<Omit<UiContextType, "strings">> & {
|
70
|
+
declare const UiProvider: ({ children, enableLogs, themeMode, primaryColor, Typography, Modal, IconButton, DeleteIcon, EditIcon, SelectIcon, CopyIcon, AnnotateIcon, SaveIcon, CloseIcon, TextField, NumberField, BoolField, EnumField, Button, pickerColors, notify, strings, }: PropsWithChildren<Partial<Omit<UiContextType, "strings">> & {
|
48
71
|
strings?: Partial<UiContextType["strings"]>;
|
49
72
|
}>) => import("react/jsx-runtime").JSX.Element;
|
50
73
|
export default UiProvider;
|
@@ -10,6 +10,12 @@ import CopyIcon from '../Icons/CopyIcon';
|
|
10
10
|
import AnnotateIcon from '../Icons/AnnotateIcon';
|
11
11
|
import Modal from '../Components/Modal';
|
12
12
|
import CloseIcon from '../Icons/CloseIcon';
|
13
|
+
import TextField from '../Components/TextField';
|
14
|
+
import NumberField from '../Components/NumberField';
|
15
|
+
import BoolField from '../Components/BoolField';
|
16
|
+
import EnumField from '../Components/EnumField';
|
17
|
+
import Button from '../Components/Button';
|
18
|
+
import SaveIcon from '../Icons/SaveIcon';
|
13
19
|
export const DefaultUiContext = {
|
14
20
|
enableLogs: true,
|
15
21
|
themeMode: 'light',
|
@@ -22,15 +28,25 @@ export const DefaultUiContext = {
|
|
22
28
|
SelectIcon,
|
23
29
|
CopyIcon,
|
24
30
|
AnnotateIcon,
|
31
|
+
SaveIcon,
|
25
32
|
CloseIcon,
|
33
|
+
TextField,
|
34
|
+
NumberField,
|
35
|
+
BoolField,
|
36
|
+
EnumField,
|
37
|
+
Button,
|
26
38
|
pickerColors: ['#ffffff', '#000000', '#ff9900', '#0099ff'],
|
27
39
|
notify,
|
28
40
|
strings: {
|
41
|
+
cancel: 'Cancel',
|
29
42
|
cannotDrawMorePolygons: 'You cannot draw more polygons',
|
30
43
|
cannotDrawMorePolylines: 'You cannot draw more polylines',
|
31
44
|
cannotDrawMoreRectangles: 'You cannot draw more rectangles',
|
32
45
|
id: 'ID',
|
46
|
+
invalidSubmission: 'Invalid submission',
|
33
47
|
mainParametersMetadata: 'Main parameters',
|
48
|
+
missingRequiredValuesInMainParameters: 'Missing required values in main parameters',
|
49
|
+
missingRequiredValuesInShapeParameters: 'Missing required values in shape {id} parameters',
|
34
50
|
polygon: 'Polygon',
|
35
51
|
polygonHelpText: 'click to draw all the polygon points, double click on the last point to close the polygon',
|
36
52
|
polyline: 'Polyline',
|
@@ -39,11 +55,18 @@ export const DefaultUiContext = {
|
|
39
55
|
rectHelpText: 'click and drag to draw the rectangle',
|
40
56
|
pointer: 'Selection',
|
41
57
|
pointerHelpText: 'click a shape to select it',
|
58
|
+
requiredField: 'This field is required',
|
59
|
+
save: 'Save',
|
60
|
+
shapesOfTypeShouldBeEqualToThreshold: 'Shapes of type {type} should be equal to {threshold}',
|
61
|
+
shapesOfTypeShouldBeGreaterThanThreshold: 'Shapes of type {type} should be greater than {threshold}',
|
62
|
+
shapesOfTypeShouldBeGreaterThanOrEqualToThreshold: 'Shapes of type {type} should be greater than or equal to {threshold}',
|
63
|
+
shapesOfTypeShouldBeLessThanThreshold: 'Shapes of type {type} should be less than {threshold}',
|
64
|
+
shapesOfTypeShouldBeLessThanOrEqualToThreshold: 'Shapes of type {type} should be less than or equal to {threshold}',
|
42
65
|
type: 'Type',
|
43
66
|
},
|
44
67
|
};
|
45
68
|
export const UiContext = createContext(DefaultUiContext);
|
46
|
-
const UiProvider = ({ children, enableLogs, themeMode, primaryColor, Typography, Modal, IconButton, DeleteIcon, EditIcon, SelectIcon, CopyIcon, AnnotateIcon, CloseIcon, pickerColors, notify, strings, }) => {
|
69
|
+
const UiProvider = ({ children, enableLogs, themeMode, primaryColor, Typography, Modal, IconButton, DeleteIcon, EditIcon, SelectIcon, CopyIcon, AnnotateIcon, SaveIcon, CloseIcon, TextField, NumberField, BoolField, EnumField, Button, pickerColors, notify, strings, }) => {
|
47
70
|
const ctx = {
|
48
71
|
enableLogs: enableLogs !== null && enableLogs !== void 0 ? enableLogs : DefaultUiContext.enableLogs,
|
49
72
|
Typography: Typography !== null && Typography !== void 0 ? Typography : DefaultUiContext.Typography,
|
@@ -54,7 +77,13 @@ const UiProvider = ({ children, enableLogs, themeMode, primaryColor, Typography,
|
|
54
77
|
SelectIcon: SelectIcon !== null && SelectIcon !== void 0 ? SelectIcon : DefaultUiContext.SelectIcon,
|
55
78
|
CopyIcon: CopyIcon !== null && CopyIcon !== void 0 ? CopyIcon : DefaultUiContext.CopyIcon,
|
56
79
|
AnnotateIcon: AnnotateIcon !== null && AnnotateIcon !== void 0 ? AnnotateIcon : DefaultUiContext.AnnotateIcon,
|
80
|
+
SaveIcon: SaveIcon !== null && SaveIcon !== void 0 ? SaveIcon : DefaultUiContext.SaveIcon,
|
57
81
|
CloseIcon: CloseIcon !== null && CloseIcon !== void 0 ? CloseIcon : DefaultUiContext.CloseIcon,
|
82
|
+
TextField: TextField !== null && TextField !== void 0 ? TextField : DefaultUiContext.TextField,
|
83
|
+
NumberField: NumberField !== null && NumberField !== void 0 ? NumberField : DefaultUiContext.NumberField,
|
84
|
+
BoolField: BoolField !== null && BoolField !== void 0 ? BoolField : DefaultUiContext.BoolField,
|
85
|
+
EnumField: EnumField !== null && EnumField !== void 0 ? EnumField : DefaultUiContext.EnumField,
|
86
|
+
Button: Button !== null && Button !== void 0 ? Button : DefaultUiContext.Button,
|
58
87
|
themeMode: themeMode !== null && themeMode !== void 0 ? themeMode : DefaultUiContext.themeMode,
|
59
88
|
primaryColor: primaryColor !== null && primaryColor !== void 0 ? primaryColor : DefaultUiContext.primaryColor,
|
60
89
|
pickerColors: pickerColors !== null && pickerColors !== void 0 ? pickerColors : DefaultUiContext.pickerColors,
|
package/dist/Types.d.ts
ADDED
package/dist/Types.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/dist/Utils/index.d.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
export declare const log: (level: "log" | "info" | "warn" | "error", enable: boolean, ...args: unknown[]) => false | void;
|
2
|
-
export declare const css: (name: string, styles: Record<string, string>, themeMode: "light" | "dark") => string;
|
2
|
+
export declare const css: (name: string, styles: Record<string, string>, themeMode: "light" | "dark" | null) => string;
|
package/dist/Utils/index.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
export const log = (level, enable, ...args) => enable && console[level](...args);
|
2
|
-
export const css = (name, styles, themeMode) => `${styles[name]} ${styles[`${name}-${themeMode}`]} react-cam-roi-${name} react-cam-roi-${name}-${themeMode}`;
|
2
|
+
export const css = (name, styles, themeMode) => `${styles[name]} ${styles[`${name}-${themeMode}`]} react-cam-roi-${name}${themeMode ? `react-cam-roi-${name}-${themeMode}` : ''}`;
|