@abidibo/react-cam-roi 0.0.8 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. package/README.md +335 -39
  2. package/dist/Components/BoolField/BoolField.module.css +60 -0
  3. package/dist/Components/BoolField/index.d.ts +5 -0
  4. package/dist/Components/BoolField/index.js +13 -0
  5. package/dist/Components/Button/Button.module.css +27 -0
  6. package/dist/Components/Button/index.d.ts +8 -0
  7. package/dist/Components/Button/index.js +15 -0
  8. package/dist/Components/EnumField/EnumField.module.css +61 -0
  9. package/dist/Components/EnumField/index.d.ts +10 -0
  10. package/dist/Components/EnumField/index.js +16 -0
  11. package/dist/Components/IconButton/IconButton.module.css +8 -3
  12. package/dist/Components/IconButton/index.d.ts +1 -0
  13. package/dist/Components/IconButton/index.js +3 -3
  14. package/dist/Components/Modal/Modal.module.css +7 -0
  15. package/dist/Components/Modal/index.d.ts +2 -1
  16. package/dist/Components/Modal/index.js +3 -3
  17. package/dist/Components/NumberField/NumberField.module.css +60 -0
  18. package/dist/Components/NumberField/index.d.ts +3 -0
  19. package/dist/Components/NumberField/index.js +13 -0
  20. package/dist/Components/RoiEditor/Canvas.d.ts +2 -0
  21. package/dist/Components/RoiEditor/Canvas.js +20 -8
  22. package/dist/Components/RoiEditor/Hooks.d.ts +13 -0
  23. package/dist/Components/RoiEditor/Hooks.js +84 -5
  24. package/dist/Components/RoiEditor/ParameterField.d.ts +9 -0
  25. package/dist/Components/RoiEditor/ParameterField.js +27 -0
  26. package/dist/Components/RoiEditor/ParametersModalForm/ParametersModalForm.module.css +5 -0
  27. package/dist/Components/RoiEditor/ParametersModalForm/index.d.ts +10 -0
  28. package/dist/Components/RoiEditor/ParametersModalForm/index.js +31 -0
  29. package/dist/Components/RoiEditor/ShapesList.js +19 -6
  30. package/dist/Components/RoiEditor/Toolbar.js +13 -3
  31. package/dist/Components/RoiEditor/Toolbar.module.css +13 -1
  32. package/dist/Components/RoiEditor/Types.d.ts +52 -2
  33. package/dist/Components/RoiEditor/Utils.d.ts +18 -1
  34. package/dist/Components/RoiEditor/Utils.js +106 -0
  35. package/dist/Components/RoiEditor/index.d.ts +3 -1
  36. package/dist/Components/RoiEditor/index.js +44 -6
  37. package/dist/Components/TextField/TextField.module.css +61 -0
  38. package/dist/Components/TextField/index.d.ts +6 -0
  39. package/dist/Components/TextField/index.js +13 -0
  40. package/dist/Components/Typography/index.d.ts +1 -0
  41. package/dist/Components/Typography/index.js +2 -2
  42. package/dist/Icons/SaveIcon.d.ts +6 -0
  43. package/dist/Icons/SaveIcon.js +5 -0
  44. package/dist/Providers/EditorProvider.d.ts +11 -2
  45. package/dist/Providers/EditorProvider.js +16 -2
  46. package/dist/Providers/UiProvider.d.ts +24 -1
  47. package/dist/Providers/UiProvider.js +30 -1
  48. package/dist/Types.d.ts +10 -0
  49. package/dist/Types.js +1 -0
  50. package/dist/Utils/index.d.ts +1 -1
  51. package/dist/Utils/index.js +1 -1
  52. package/package.json +7 -2
  53. package/dist/Components/RoiEditor/ParametersModalForm.d.ts +0 -5
  54. 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 0 1rem;
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 | boolean;
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,9 @@
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;
5
7
  };
6
8
  declare const RoiEditor: React.FC<RoiEditorProps>;
7
9
  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
- const { themeMode, enableLogs, pickerColors } = useContext(UiContext);
14
+ const RoiEditor = ({ imageUrl, configuration, onSubmit, initialData }) => {
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
- }, [shapes]);
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, { 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,6 @@
1
+ import { FieldProps } from '../../Types';
2
+ export interface TextFieldProps extends FieldProps<string> {
3
+ type?: 'text' | 'email' | 'password';
4
+ }
5
+ declare const TextField: React.FC<TextFieldProps>;
6
+ export default TextField;
@@ -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;
@@ -3,6 +3,7 @@ export type TypographyProps = {
3
3
  className?: string;
4
4
  variant?: any;
5
5
  component?: any;
6
+ style?: React.CSSProperties;
6
7
  };
7
8
  declare const Typography: React.FC<TypographyProps>;
8
9
  export default Typography;
@@ -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,6 @@
1
+ type SaveIconProps = {
2
+ color?: string;
3
+ style?: React.CSSProperties;
4
+ };
5
+ declare const SaveIcon: React.FC<SaveIconProps>;
6
+ export default SaveIcon;
@@ -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,25 @@
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;
12
21
  };
13
22
  export declare const EditorContext: import("react").Context<EditorContextType | undefined>;
14
23
  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;
24
+ declare const EditorProvider: ({ children, hideForbiddenTools, activeTool, setActiveTool, activeColor, setActiveColor, shapes, addShape, addShapes, removeShape, configuration, metadata, setMetadata, onSubmit, }: PropsWithChildren<EditorContextType>) => import("react/jsx-runtime").JSX.Element;
16
25
  export default EditorProvider;
@@ -8,7 +8,21 @@ 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: { activeTool, setActiveTool, activeColor, setActiveColor, shapes, addShape, removeShape, configuration }, children: children }));
11
+ const EditorProvider = ({ children, hideForbiddenTools, activeTool, setActiveTool, activeColor, setActiveColor, shapes, addShape, addShapes, removeShape, configuration, metadata, setMetadata, onSubmit, }) => {
12
+ return (_jsx(EditorContext.Provider, { value: {
13
+ hideForbiddenTools,
14
+ activeTool,
15
+ setActiveTool,
16
+ activeColor,
17
+ setActiveColor,
18
+ shapes,
19
+ addShape,
20
+ addShapes,
21
+ removeShape,
22
+ configuration,
23
+ metadata,
24
+ setMetadata,
25
+ onSubmit,
26
+ }, children: children }));
13
27
  };
14
28
  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,
@@ -0,0 +1,10 @@
1
+ export interface FieldProps<T> {
2
+ onChange: (value: T) => void;
3
+ value: T;
4
+ label: string;
5
+ helperText?: string;
6
+ error?: boolean;
7
+ required?: boolean;
8
+ readOnly?: boolean;
9
+ disabled?: boolean;
10
+ }
package/dist/Types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -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;
@@ -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}` : ''}`;