@abidibo/react-cam-roi 0.0.8 → 0.0.10

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 (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}` : ''}`;