@pie-element/hotspot 11.1.2-next.2 → 11.1.2

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 (234) hide show
  1. package/CHANGELOG.json +997 -0
  2. package/CHANGELOG.md +2220 -0
  3. package/LICENSE.md +5 -0
  4. package/README.md +1 -0
  5. package/configure/CHANGELOG.json +682 -0
  6. package/configure/CHANGELOG.md +1957 -0
  7. package/configure/lib/DeleteWidget.js +64 -0
  8. package/configure/lib/DeleteWidget.js.map +1 -0
  9. package/configure/lib/button.js +42 -0
  10. package/configure/lib/button.js.map +1 -0
  11. package/configure/lib/buttons/circle.js +33 -0
  12. package/configure/lib/buttons/circle.js.map +1 -0
  13. package/configure/lib/buttons/polygon.js +39 -0
  14. package/configure/lib/buttons/polygon.js.map +1 -0
  15. package/configure/lib/buttons/rectangle.js +39 -0
  16. package/configure/lib/buttons/rectangle.js.map +1 -0
  17. package/configure/lib/defaults.js +155 -0
  18. package/configure/lib/defaults.js.map +1 -0
  19. package/configure/lib/hotspot-circle.js +192 -0
  20. package/configure/lib/hotspot-circle.js.map +1 -0
  21. package/configure/lib/hotspot-container.js +320 -0
  22. package/configure/lib/hotspot-container.js.map +1 -0
  23. package/configure/lib/hotspot-drawable.js +519 -0
  24. package/configure/lib/hotspot-drawable.js.map +1 -0
  25. package/configure/lib/hotspot-palette.js +107 -0
  26. package/configure/lib/hotspot-palette.js.map +1 -0
  27. package/configure/lib/hotspot-polygon.js +293 -0
  28. package/configure/lib/hotspot-polygon.js.map +1 -0
  29. package/configure/lib/hotspot-rectangle.js +190 -0
  30. package/configure/lib/hotspot-rectangle.js.map +1 -0
  31. package/configure/lib/icons.js +7 -0
  32. package/configure/lib/icons.js.map +1 -0
  33. package/configure/lib/image-konva.js +66 -0
  34. package/configure/lib/image-konva.js.map +1 -0
  35. package/configure/lib/index.js +194 -0
  36. package/configure/lib/index.js.map +1 -0
  37. package/configure/lib/root.js +330 -0
  38. package/configure/lib/root.js.map +1 -0
  39. package/configure/lib/shapes/circle.js +84 -0
  40. package/configure/lib/shapes/circle.js.map +1 -0
  41. package/configure/lib/shapes/index.js +50 -0
  42. package/configure/lib/shapes/index.js.map +1 -0
  43. package/configure/lib/shapes/polygon.js +82 -0
  44. package/configure/lib/shapes/polygon.js.map +1 -0
  45. package/configure/lib/shapes/rectagle.js +84 -0
  46. package/configure/lib/shapes/rectagle.js.map +1 -0
  47. package/configure/lib/shapes/utils.js +21 -0
  48. package/configure/lib/shapes/utils.js.map +1 -0
  49. package/configure/lib/upload-control.js +41 -0
  50. package/configure/lib/upload-control.js.map +1 -0
  51. package/configure/lib/utils.js +185 -0
  52. package/configure/lib/utils.js.map +1 -0
  53. package/configure/package.json +26 -0
  54. package/configure/src/DeleteWidget.jsx +51 -0
  55. package/configure/src/__tests__/DeleteWidget.test.jsx +366 -0
  56. package/configure/src/__tests__/button.test.jsx +198 -0
  57. package/configure/src/__tests__/hotspot-circle.test.jsx +259 -0
  58. package/configure/src/__tests__/hotspot-container.test.js +366 -0
  59. package/configure/src/__tests__/hotspot-drawable.test.js +271 -0
  60. package/configure/src/__tests__/hotspot-palette.test.jsx +71 -0
  61. package/configure/src/__tests__/image-konva.test.jsx +226 -0
  62. package/configure/src/__tests__/index.test.js +329 -0
  63. package/configure/src/__tests__/root.test.js +400 -0
  64. package/configure/src/__tests__/utils.test.js +241 -0
  65. package/configure/src/button.jsx +35 -0
  66. package/configure/src/buttons/circle.jsx +18 -0
  67. package/configure/src/buttons/polygon.jsx +29 -0
  68. package/configure/src/buttons/rectangle.jsx +29 -0
  69. package/configure/src/defaults.js +109 -0
  70. package/configure/src/hotspot-circle.jsx +183 -0
  71. package/configure/src/hotspot-container.jsx +330 -0
  72. package/configure/src/hotspot-drawable.jsx +527 -0
  73. package/configure/src/hotspot-palette.jsx +90 -0
  74. package/configure/src/hotspot-polygon.jsx +294 -0
  75. package/configure/src/hotspot-rectangle.jsx +169 -0
  76. package/configure/src/icons.js +5 -0
  77. package/configure/src/image-konva.jsx +63 -0
  78. package/configure/src/index.js +208 -0
  79. package/configure/src/root.jsx +346 -0
  80. package/configure/src/shapes/circle.js +81 -0
  81. package/configure/src/shapes/index.js +4 -0
  82. package/configure/src/shapes/polygon.js +81 -0
  83. package/configure/src/shapes/rectagle.js +82 -0
  84. package/configure/src/shapes/utils.js +16 -0
  85. package/configure/src/upload-control.jsx +33 -0
  86. package/configure/src/utils.js +210 -0
  87. package/controller/CHANGELOG.json +362 -0
  88. package/controller/CHANGELOG.md +1304 -0
  89. package/controller/lib/defaults.js +33 -0
  90. package/controller/lib/defaults.js.map +1 -0
  91. package/controller/lib/index.js +341 -0
  92. package/controller/lib/index.js.map +1 -0
  93. package/controller/lib/utils.js +32 -0
  94. package/controller/lib/utils.js.map +1 -0
  95. package/controller/package.json +18 -0
  96. package/controller/src/__tests__/index.test.js +419 -0
  97. package/controller/src/__tests__/utils.test.js +5 -0
  98. package/controller/src/defaults.js +19 -0
  99. package/controller/src/index.js +328 -0
  100. package/controller/src/utils.js +29 -0
  101. package/docs/config-schema.json +2023 -0
  102. package/docs/config-schema.json.md +1495 -0
  103. package/docs/demo/config.js +8 -0
  104. package/docs/demo/generate.js +118 -0
  105. package/docs/demo/index.html +1 -0
  106. package/docs/demo/session.js +11 -0
  107. package/docs/pie-schema.json +1204 -0
  108. package/docs/pie-schema.json.md +851 -0
  109. package/lib/hotspot/circle.js +156 -0
  110. package/lib/hotspot/circle.js.map +1 -0
  111. package/lib/hotspot/container.js +206 -0
  112. package/lib/hotspot/container.js.map +1 -0
  113. package/lib/hotspot/icons.js +8 -0
  114. package/lib/hotspot/icons.js.map +1 -0
  115. package/lib/hotspot/image-konva-tooltip.js +86 -0
  116. package/lib/hotspot/image-konva-tooltip.js.map +1 -0
  117. package/lib/hotspot/index.js +163 -0
  118. package/lib/hotspot/index.js.map +1 -0
  119. package/lib/hotspot/polygon.js +203 -0
  120. package/lib/hotspot/polygon.js.map +1 -0
  121. package/lib/hotspot/rectangle.js +175 -0
  122. package/lib/hotspot/rectangle.js.map +1 -0
  123. package/lib/index.js +213 -0
  124. package/lib/index.js.map +1 -0
  125. package/lib/session-updater.js +42 -0
  126. package/lib/session-updater.js.map +1 -0
  127. package/package.json +18 -83
  128. package/src/__tests__/container.test.jsx +58 -0
  129. package/src/__tests__/index.test.js +123 -0
  130. package/src/__tests__/session-updater.test.jsx +69 -0
  131. package/src/hotspot/__tests__/circle.test.jsx +464 -0
  132. package/src/hotspot/__tests__/container.test.jsx +546 -0
  133. package/src/hotspot/__tests__/image-konva-tooltip.test.jsx +510 -0
  134. package/src/hotspot/__tests__/polygon.test.jsx +502 -0
  135. package/src/hotspot/__tests__/rectangle.test.jsx +418 -0
  136. package/src/hotspot/circle.jsx +152 -0
  137. package/src/hotspot/container.jsx +217 -0
  138. package/src/hotspot/icons.js +7 -0
  139. package/src/hotspot/image-konva-tooltip.jsx +76 -0
  140. package/src/hotspot/index.jsx +165 -0
  141. package/src/hotspot/polygon.jsx +195 -0
  142. package/src/hotspot/rectangle.jsx +171 -0
  143. package/src/index.js +226 -0
  144. package/src/session-updater.js +29 -0
  145. package/configure.js +0 -2
  146. package/controller.js +0 -1
  147. package/dist/author/DeleteWidget.d.ts +0 -38
  148. package/dist/author/DeleteWidget.js +0 -46
  149. package/dist/author/button.d.ts +0 -31
  150. package/dist/author/button.js +0 -27
  151. package/dist/author/buttons/circle.d.ts +0 -18
  152. package/dist/author/buttons/circle.js +0 -25
  153. package/dist/author/buttons/polygon.d.ts +0 -18
  154. package/dist/author/buttons/polygon.js +0 -36
  155. package/dist/author/buttons/rectangle.d.ts +0 -18
  156. package/dist/author/buttons/rectangle.js +0 -36
  157. package/dist/author/defaults.d.ts +0 -157
  158. package/dist/author/defaults.js +0 -119
  159. package/dist/author/hotspot-circle.d.ts +0 -21
  160. package/dist/author/hotspot-circle.js +0 -124
  161. package/dist/author/hotspot-container.d.ts +0 -29
  162. package/dist/author/hotspot-container.js +0 -210
  163. package/dist/author/hotspot-drawable.d.ts +0 -31
  164. package/dist/author/hotspot-drawable.js +0 -312
  165. package/dist/author/hotspot-palette.d.ts +0 -14
  166. package/dist/author/hotspot-palette.js +0 -72
  167. package/dist/author/hotspot-polygon.d.ts +0 -38
  168. package/dist/author/hotspot-polygon.js +0 -200
  169. package/dist/author/hotspot-rectangle.d.ts +0 -20
  170. package/dist/author/hotspot-rectangle.js +0 -119
  171. package/dist/author/icons.d.ts +0 -9
  172. package/dist/author/icons.js +0 -4
  173. package/dist/author/image-konva.d.ts +0 -19
  174. package/dist/author/image-konva.js +0 -49
  175. package/dist/author/index.d.ts +0 -52
  176. package/dist/author/index.js +0 -143
  177. package/dist/author/root.d.ts +0 -15
  178. package/dist/author/root.js +0 -215
  179. package/dist/author/shapes/circle.d.ts +0 -18
  180. package/dist/author/shapes/circle.js +0 -47
  181. package/dist/author/shapes/index.d.ts +0 -12
  182. package/dist/author/shapes/polygon.d.ts +0 -19
  183. package/dist/author/shapes/polygon.js +0 -51
  184. package/dist/author/shapes/rectagle.d.ts +0 -18
  185. package/dist/author/shapes/rectagle.js +0 -57
  186. package/dist/author/shapes/utils.d.ts +0 -19
  187. package/dist/author/shapes/utils.js +0 -16
  188. package/dist/author/upload-control.d.ts +0 -29
  189. package/dist/author/upload-control.js +0 -28
  190. package/dist/author/utils.d.ts +0 -24
  191. package/dist/author/utils.js +0 -83
  192. package/dist/browser/ReactKonva-DI5WIo8o.js +0 -19336
  193. package/dist/browser/ReactKonva-DI5WIo8o.js.map +0 -1
  194. package/dist/browser/author/index.js +0 -41646
  195. package/dist/browser/author/index.js.map +0 -1
  196. package/dist/browser/browser-CfnAFove.js +0 -219
  197. package/dist/browser/browser-CfnAFove.js.map +0 -1
  198. package/dist/browser/controller/index.js +0 -198
  199. package/dist/browser/controller/index.js.map +0 -1
  200. package/dist/browser/delivery/index.js +0 -2460
  201. package/dist/browser/delivery/index.js.map +0 -1
  202. package/dist/browser/dist-C78LDz6R.js +0 -96
  203. package/dist/browser/dist-C78LDz6R.js.map +0 -1
  204. package/dist/browser/hotspot.css +0 -2
  205. package/dist/controller/defaults.d.ts +0 -35
  206. package/dist/controller/defaults.js +0 -29
  207. package/dist/controller/index.d.ts +0 -22
  208. package/dist/controller/index.js +0 -154
  209. package/dist/controller/utils.d.ts +0 -10
  210. package/dist/controller/utils.js +0 -12
  211. package/dist/delivery/hotspot/circle.d.ts +0 -19
  212. package/dist/delivery/hotspot/circle.js +0 -100
  213. package/dist/delivery/hotspot/container.d.ts +0 -16
  214. package/dist/delivery/hotspot/container.js +0 -150
  215. package/dist/delivery/hotspot/icons.d.ts +0 -10
  216. package/dist/delivery/hotspot/icons.js +0 -4
  217. package/dist/delivery/hotspot/image-konva-tooltip.d.ts +0 -19
  218. package/dist/delivery/hotspot/image-konva-tooltip.js +0 -66
  219. package/dist/delivery/hotspot/index.d.ts +0 -17
  220. package/dist/delivery/hotspot/index.js +0 -114
  221. package/dist/delivery/hotspot/polygon.d.ts +0 -21
  222. package/dist/delivery/hotspot/polygon.js +0 -108
  223. package/dist/delivery/hotspot/rectangle.d.ts +0 -19
  224. package/dist/delivery/hotspot/rectangle.js +0 -104
  225. package/dist/delivery/index.d.ts +0 -20
  226. package/dist/delivery/index.js +0 -107
  227. package/dist/delivery/session-updater.d.ts +0 -10
  228. package/dist/delivery/session-updater.js +0 -14
  229. package/dist/index.d.ts +0 -1
  230. package/dist/index.iife.d.ts +0 -8
  231. package/dist/index.iife.js +0 -169
  232. package/dist/index.js +0 -2
  233. package/dist/runtime-support.d.ts +0 -12
  234. package/dist/runtime-support.js +0 -12
@@ -0,0 +1,400 @@
1
+ import { render } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { Root } from '../root';
4
+ import defaultValues from '../defaults';
5
+
6
+ jest.mock('react-konva', () => {
7
+ const React = require('react');
8
+ return {
9
+ Stage: ({ children, ...props }) => React.createElement('div', { 'data-testid': 'stage', ...props }, children),
10
+ Layer: ({ children, ...props }) => React.createElement('div', { 'data-testid': 'layer', ...props }, children),
11
+ Rect: (props) => React.createElement('div', { 'data-testid': 'rect', ...props }),
12
+ Circle: (props) => React.createElement('div', { 'data-testid': 'circle', ...props }),
13
+ Line: (props) => React.createElement('div', { 'data-testid': 'line', ...props }),
14
+ Group: ({ children, ...props }) => React.createElement('div', { 'data-testid': 'group', ...props }, children),
15
+ Image: (props) => React.createElement('div', { 'data-testid': 'image', ...props }),
16
+ };
17
+ });
18
+
19
+ jest.mock('@pie-lib/config-ui', () => ({
20
+ InputContainer: (props) => <div {...props}>{props.children}</div>,
21
+ NumberTextField: (props) => <input type="number" {...props} />,
22
+ choiceUtils: {
23
+ firstAvailableIndex: jest.fn(),
24
+ },
25
+ settings: {
26
+ Panel: (props) => <div {...props} />,
27
+ toggle: jest.fn(),
28
+ radio: jest.fn(),
29
+ dropdown: jest.fn(),
30
+ },
31
+ layout: {
32
+ ConfigLayout: ({ children }) => <div>{children}</div>,
33
+ },
34
+ }));
35
+
36
+ const model = () => ({
37
+ prompt: 'This is the question prompt',
38
+ imageUrl: 'https://cdn.fluence.net/image/0240eb1455ce4c4bb6180232347b6aef_W',
39
+ shapes: {
40
+ rectangles: [
41
+ {
42
+ id: '0',
43
+ height: 140,
44
+ width: 130,
45
+ x: 1,
46
+ y: 1,
47
+ correct: true,
48
+ },
49
+ {
50
+ id: '1',
51
+ height: 140,
52
+ width: 130,
53
+ x: 140,
54
+ y: 1,
55
+ },
56
+ {
57
+ id: '2',
58
+ height: 140,
59
+ width: 130,
60
+ x: 280,
61
+ y: 1,
62
+ },
63
+ ],
64
+ polygons: [
65
+ {
66
+ points: [
67
+ { x: 1, y: 148 },
68
+ { x: 1, y: 288 },
69
+ { y: 288, x: 129 },
70
+ { y: 148, x: 129 },
71
+ ],
72
+ correct: true,
73
+ id: '3',
74
+ },
75
+ {
76
+ id: '4',
77
+ points: [
78
+ { y: 151, x: 141 },
79
+ { y: 289, x: 141 },
80
+ { y: 289, x: 269 },
81
+ { x: 269, y: 151 },
82
+ ],
83
+ correct: false,
84
+ },
85
+ {
86
+ points: [
87
+ { x: 279, y: 149.99999999999997 },
88
+ { x: 279, y: 289 },
89
+ { x: 407, y: 289 },
90
+ {
91
+ x: 407,
92
+ y: 149.99999999999997,
93
+ },
94
+ ],
95
+ correct: false,
96
+ id: '5',
97
+ },
98
+ ],
99
+ circles: [
100
+ {
101
+ id: '6',
102
+ radius: 70,
103
+ x: 100,
104
+ y: 100,
105
+ correct: false,
106
+ },
107
+ ],
108
+ },
109
+ dimensions: { height: 300, width: 400 },
110
+ hotspotColor: 'rgba(137, 183, 244, 0.65)',
111
+ hotspotList: ['rgba(137, 183, 244, 0.65)', 'rgba(217, 30, 24, 0.65)', 'rgba(254, 241, 96, 0.65)'],
112
+ outlineColor: 'blue',
113
+ outlineList: ['blue', 'red', 'yellow'],
114
+ configure: {},
115
+ multipleCorrect: true,
116
+ partialScoring: false,
117
+ });
118
+
119
+ describe('Root', () => {
120
+ let initialModel = model();
121
+
122
+ describe('logic', () => {
123
+ let onColorChanged = jest.fn();
124
+
125
+ const createInstance = (config, onUpdateImageDimension, onUpdateShapes) => {
126
+ const props = {
127
+ classes: {},
128
+ configuration: config || defaultValues.configuration,
129
+ model: {
130
+ ...initialModel,
131
+ dimensions: { width: 200, height: 300 },
132
+ shapes: {
133
+ rectangles: [{ x: 10, y: 10, height: 100, width: 100 }],
134
+ polygons: [
135
+ {
136
+ points: [
137
+ { x: 0, y: 200 },
138
+ { x: 200, y: 200 },
139
+ { x: 100, y: 300 },
140
+ ],
141
+ },
142
+ ],
143
+ },
144
+ },
145
+ onColorChanged,
146
+ onUpdateImageDimension,
147
+ onUpdateShapes,
148
+ };
149
+
150
+ return new Root(props);
151
+ };
152
+
153
+ describe('handleColorChange', () => {
154
+ it('calls onColorChanged', () => {
155
+ const instance = createInstance();
156
+ instance.handleColorChange('type', 'color');
157
+
158
+ expect(onColorChanged).toHaveBeenLastCalledWith('typeColor', 'color');
159
+ });
160
+ });
161
+
162
+ describe('KEEP IMAGE ASPECT RATIO: handleOnUpdateImageDimensions: calls onUpdateImageDimension & onUpdateShapes', () => {
163
+ let onUpdateImageDimension = jest.fn();
164
+ let onUpdateShapes = jest.fn();
165
+
166
+ it('increase width with 100%:', () => {
167
+ const instance = createInstance(undefined, onUpdateImageDimension, onUpdateShapes);
168
+ instance.handleOnUpdateImageDimensions(400, 'width');
169
+
170
+ expect(onUpdateImageDimension).toBeCalledWith({
171
+ width: 400,
172
+ height: 600,
173
+ });
174
+ expect(onUpdateShapes).toBeCalledWith({
175
+ rectangles: [{ x: 20, y: 20, height: 200, width: 200, index: 0 }],
176
+ polygons: [
177
+ {
178
+ points: [
179
+ { x: 0, y: 400 },
180
+ { x: 400, y: 400 },
181
+ { x: 200, y: 600 },
182
+ ],
183
+ index: 1,
184
+ },
185
+ ],
186
+ circles: [],
187
+ });
188
+ });
189
+
190
+ it('decrease width with 50%', () => {
191
+ const instance = createInstance(undefined, onUpdateImageDimension, onUpdateShapes);
192
+ instance.handleOnUpdateImageDimensions(100, 'width');
193
+
194
+ expect(onUpdateImageDimension).toBeCalledWith({
195
+ width: 100,
196
+ height: 150,
197
+ });
198
+ expect(onUpdateShapes).toBeCalledWith({
199
+ rectangles: [{ x: 5, y: 5, height: 50, width: 50, index: 0 }],
200
+ polygons: [
201
+ {
202
+ points: [
203
+ { x: 0, y: 100 },
204
+ { x: 100, y: 100 },
205
+ { x: 50, y: 150 },
206
+ ],
207
+ index: 1,
208
+ },
209
+ ],
210
+ circles: [],
211
+ });
212
+ });
213
+
214
+ it('increase height with 50%:', () => {
215
+ const instance = createInstance(undefined, onUpdateImageDimension, onUpdateShapes);
216
+ instance.handleOnUpdateImageDimensions(450, 'height');
217
+
218
+ expect(onUpdateImageDimension).toBeCalledWith({
219
+ width: 300,
220
+ height: 450,
221
+ });
222
+ expect(onUpdateShapes).toBeCalledWith({
223
+ rectangles: [{ x: 15, y: 15, height: 150, width: 150, index: 0 }],
224
+ polygons: [
225
+ {
226
+ points: [
227
+ { x: 0, y: 300 },
228
+ { x: 300, y: 300 },
229
+ { x: 150, y: 450 },
230
+ ],
231
+ index: 1,
232
+ },
233
+ ],
234
+ circles: [],
235
+ });
236
+ });
237
+
238
+ it('decrease height with 10%', () => {
239
+ const instance = createInstance(undefined, onUpdateImageDimension, onUpdateShapes);
240
+ instance.handleOnUpdateImageDimensions(270, 'height');
241
+
242
+ expect(onUpdateImageDimension).toBeCalledWith({
243
+ width: 180,
244
+ height: 270,
245
+ });
246
+ expect(onUpdateShapes).toBeCalledWith({
247
+ rectangles: [{ x: 9, y: 9, height: 90, width: 90, index: 0 }],
248
+ polygons: [
249
+ {
250
+ points: [
251
+ { x: 0, y: 180 },
252
+ { x: 180, y: 180 },
253
+ { x: 90, y: 270 },
254
+ ],
255
+ index: 1,
256
+ },
257
+ ],
258
+ circles: [],
259
+ });
260
+ });
261
+ });
262
+
263
+ describe('DO NOT KEEP IMAGE ASPECT RATIO: handleOnUpdateImageDimensions: calls onUpdateImageDimension & onUpdateShapes', () => {
264
+ let onUpdateImageDimension = jest.fn();
265
+ let onUpdateShapes = jest.fn();
266
+
267
+ it('increase width with 100%:', () => {
268
+ const instance = createInstance(
269
+ {
270
+ ...defaultValues.configuration,
271
+ preserveAspectRatio: {
272
+ enabled: false,
273
+ },
274
+ },
275
+ onUpdateImageDimension,
276
+ onUpdateShapes,
277
+ );
278
+ instance.handleOnUpdateImageDimensions(400, 'width');
279
+
280
+ expect(onUpdateImageDimension).toBeCalledWith({
281
+ width: 400,
282
+ height: 300,
283
+ });
284
+ expect(onUpdateShapes).toBeCalledWith({
285
+ rectangles: [{ x: 20, y: 10, height: 100, width: 200, index: 0 }],
286
+ polygons: [
287
+ {
288
+ points: [
289
+ { x: 0, y: 200 },
290
+ { x: 400, y: 200 },
291
+ { x: 200, y: 300 },
292
+ ],
293
+ index: 1,
294
+ },
295
+ ],
296
+ circles: [],
297
+ });
298
+ });
299
+
300
+ it('decrease width with 50%', () => {
301
+ const instance = createInstance(
302
+ {
303
+ ...defaultValues.configuration,
304
+ preserveAspectRatio: {
305
+ enabled: false,
306
+ },
307
+ },
308
+ onUpdateImageDimension,
309
+ onUpdateShapes,
310
+ );
311
+ instance.handleOnUpdateImageDimensions(100, 'width');
312
+
313
+ expect(onUpdateImageDimension).toBeCalledWith({
314
+ width: 100,
315
+ height: 300,
316
+ });
317
+ expect(onUpdateShapes).toBeCalledWith({
318
+ rectangles: [{ x: 5, y: 10, height: 100, width: 50, index: 0 }],
319
+ polygons: [
320
+ {
321
+ points: [
322
+ { x: 0, y: 200 },
323
+ { x: 100, y: 200 },
324
+ { x: 50, y: 300 },
325
+ ],
326
+ index: 1,
327
+ },
328
+ ],
329
+ circles: [],
330
+ });
331
+ });
332
+
333
+ it('increase height with 50%:', () => {
334
+ const instance = createInstance(
335
+ {
336
+ ...defaultValues.configuration,
337
+ preserveAspectRatio: {
338
+ enabled: false,
339
+ },
340
+ },
341
+ onUpdateImageDimension,
342
+ onUpdateShapes,
343
+ );
344
+ instance.handleOnUpdateImageDimensions(450, 'height');
345
+
346
+ expect(onUpdateImageDimension).toBeCalledWith({
347
+ width: 200,
348
+ height: 450,
349
+ });
350
+ expect(onUpdateShapes).toBeCalledWith({
351
+ rectangles: [{ x: 10, y: 15, height: 150, width: 100, index: 0 }],
352
+ polygons: [
353
+ {
354
+ index: 1,
355
+ points: [
356
+ { x: 0, y: 300 },
357
+ { x: 200, y: 300 },
358
+ { x: 100, y: 450 },
359
+ ],
360
+ },
361
+ ],
362
+ circles: [],
363
+ });
364
+ });
365
+
366
+ it('decrease height with 10%', () => {
367
+ const instance = createInstance(
368
+ {
369
+ ...defaultValues.configuration,
370
+ preserveAspectRatio: {
371
+ enabled: false,
372
+ },
373
+ },
374
+ onUpdateImageDimension,
375
+ onUpdateShapes,
376
+ );
377
+ instance.handleOnUpdateImageDimensions(270, 'height');
378
+
379
+ expect(onUpdateImageDimension).toBeCalledWith({
380
+ width: 200,
381
+ height: 270,
382
+ });
383
+ expect(onUpdateShapes).toBeCalledWith({
384
+ rectangles: [{ x: 10, y: 9, height: 90, width: 100, index: 0 }],
385
+ polygons: [
386
+ {
387
+ points: [
388
+ { x: 0, y: 180 },
389
+ { x: 200, y: 180 },
390
+ { x: 100, y: 270 },
391
+ ],
392
+ index: 1,
393
+ },
394
+ ],
395
+ circles: [],
396
+ });
397
+ });
398
+ });
399
+ });
400
+ });
@@ -0,0 +1,241 @@
1
+ import React from 'react';
2
+ import { updateImageDimensions, getUpdatedRectangle, getUpdatedPolygon, getAllShapes, groupShapes } from '../utils';
3
+
4
+ const width = 200;
5
+ const height = 100;
6
+ const imageDimensions = { width, height };
7
+
8
+ describe('updateImageDimensions', () => {
9
+ it.each`
10
+ initialDimensions | nextDimensions | keepAspectRatio | resizeType | expectedWidth | expectedHeight
11
+ ${imageDimensions} | ${{
12
+ width,
13
+ height: 300,
14
+ }} | ${true} | ${'height'} | ${600} | ${300}
15
+ ${imageDimensions} | ${{
16
+ width: 400,
17
+ height,
18
+ }} | ${true} | ${'width'} | ${400} | ${200}
19
+ ${imageDimensions} | ${{
20
+ width,
21
+ height: 300,
22
+ }} | ${true} | ${undefined} | ${200} | ${100}
23
+ ${imageDimensions} | ${{
24
+ width: 600,
25
+ height,
26
+ }} | ${true} | ${undefined} | ${600} | ${300}
27
+ ${imageDimensions} | ${{
28
+ width,
29
+ height: 300,
30
+ }} | ${false} | ${'height'} | ${200} | ${300}
31
+ ${imageDimensions} | ${{
32
+ width: 600,
33
+ height,
34
+ }} | ${false} | ${'width'} | ${600} | ${100}
35
+ ${imageDimensions} | ${{
36
+ width: 10,
37
+ height: 10,
38
+ }} | ${false} | ${undefined} | ${10} | ${10}
39
+ `(
40
+ 'initialDimensions = $initialDimensions, nextDimensions = $nextDimensions, keepAspectRatio = $keepAspectRatio, resizeType = $resizeType => width = $expectedWidth & height = $expectedHeight',
41
+ async ({ initialDimensions, nextDimensions, keepAspectRatio, resizeType, expectedWidth, expectedHeight }) => {
42
+ const result = updateImageDimensions(initialDimensions, nextDimensions, keepAspectRatio, resizeType);
43
+
44
+ expect(result).toEqual({
45
+ width: expectedWidth,
46
+ height: expectedHeight,
47
+ });
48
+ },
49
+ );
50
+ });
51
+
52
+ describe('getUpdatedRectangle', () => {
53
+ const rectangle = (x, y, w, h) => ({ x, y, width: w, height: h });
54
+ const heightUpdateLarge = { width, height: 300 };
55
+ const heightUpdateSmall = { width, height: 50 };
56
+ const widthUpdateLarge = { width: 300, height };
57
+ const widthUpdateSmall = { width: 100, height };
58
+ const bothUpdate = { width: 20, height: 50 };
59
+
60
+ it.each`
61
+ initialDimensions | nextDimensions | shape | expected
62
+ ${imageDimensions} | ${heightUpdateLarge} | ${rectangle(10, 10, 100, 50)} | ${rectangle(10, 30, 100, 150)}
63
+ ${imageDimensions} | ${heightUpdateSmall} | ${rectangle(10, 10, 100, 50)} | ${rectangle(10, 5, 100, 25)}
64
+ ${imageDimensions} | ${bothUpdate} | ${rectangle(10, 10, 100, 50)} | ${rectangle(1, 5, 10, 25)}
65
+ ${imageDimensions} | ${widthUpdateLarge} | ${rectangle(10, 10, 100, 50)} | ${rectangle(15, 10, 150, 50)}
66
+ ${imageDimensions} | ${widthUpdateSmall} | ${rectangle(10, 10, 100, 50)} | ${rectangle(5, 10, 50, 50)}
67
+ `(
68
+ 'initialDimensions = $initialDimensions, nextDimensions = $nextDimensions, shape = $shape => $expected',
69
+ async ({ initialDimensions, nextDimensions, shape, expected }) => {
70
+ const result = getUpdatedRectangle(initialDimensions, nextDimensions, shape);
71
+
72
+ expect(result).toEqual(expected);
73
+ },
74
+ );
75
+ });
76
+
77
+ describe('getUpdatedPolygon', () => {
78
+ const updatedDimensions = { width: width / 2, height: height * 2 };
79
+
80
+ const point = (x, y) => ({ x, y });
81
+ const updatedPoint = (x, y) => ({ x: x / 2, y: y * 2 });
82
+
83
+ const triangle = [point(10, 10), point(100, 10), point(100, 100)];
84
+ const triangleUpdated = [updatedPoint(10, 10), updatedPoint(100, 10), updatedPoint(100, 100)];
85
+
86
+ const square = [point(10, 10), point(100, 10), point(100, 100), point(10, 100)];
87
+ const squareUpdated = [updatedPoint(10, 10), updatedPoint(100, 10), updatedPoint(100, 100), updatedPoint(10, 100)];
88
+
89
+ const pentagon = [point(10, 10), point(20, 0), point(30, 0), point(40, 10), point(25, 20)];
90
+ const pentagonUpdated = [
91
+ updatedPoint(10, 10),
92
+ updatedPoint(20, 0),
93
+ updatedPoint(30, 0),
94
+ updatedPoint(40, 10),
95
+ updatedPoint(25, 20),
96
+ ];
97
+
98
+ const hexagon = [point(10, 10), point(20, 0), point(30, 0), point(40, 10), point(30, 20), point(20, 20)];
99
+ const hexagonUpdated = [
100
+ updatedPoint(10, 10),
101
+ updatedPoint(20, 0),
102
+ updatedPoint(30, 0),
103
+ updatedPoint(40, 10),
104
+ updatedPoint(30, 20),
105
+ updatedPoint(20, 20),
106
+ ];
107
+
108
+ const polygon = (points) => ({ points });
109
+
110
+ it.each`
111
+ initialDimensions | nextDimensions | shape | expected
112
+ ${imageDimensions} | ${updatedDimensions} | ${polygon(triangle)} | ${polygon(triangleUpdated)}
113
+ ${imageDimensions} | ${updatedDimensions} | ${polygon(square)} | ${polygon(squareUpdated)}
114
+ ${imageDimensions} | ${updatedDimensions} | ${polygon(pentagon)} | ${polygon(pentagonUpdated)}
115
+ ${imageDimensions} | ${updatedDimensions} | ${polygon(hexagon)} | ${polygon(hexagonUpdated)}
116
+ `(
117
+ 'initialDimensions = $initialDimensions, nextDimensions = $nextDimensions, shape = $shape => $expected',
118
+ async ({ initialDimensions, nextDimensions, shape, expected }) => {
119
+ const result = getUpdatedPolygon(initialDimensions, nextDimensions, shape);
120
+
121
+ expect(result).toEqual(expected);
122
+ },
123
+ );
124
+ });
125
+
126
+ const shapesArray = [
127
+ {
128
+ height: 100,
129
+ width: 100,
130
+ x: 1,
131
+ y: 1,
132
+ group: 'rectangles',
133
+ index: 0,
134
+ },
135
+ {
136
+ height: 200,
137
+ width: 200,
138
+ x: 200,
139
+ y: 1,
140
+ group: 'rectangles',
141
+ index: 1,
142
+ },
143
+ {
144
+ points: [
145
+ { x: 1, y: 200 },
146
+ { x: 1, y: 200 },
147
+ { y: 200, x: 200 },
148
+ { y: 200, x: 200 },
149
+ ],
150
+ group: 'polygons',
151
+ index: 2,
152
+ },
153
+ {
154
+ points: [
155
+ { x: 200, y: 100 },
156
+ { x: 200, y: 200 },
157
+ { x: 400, y: 200 },
158
+ { x: 400, y: 200 },
159
+ ],
160
+ group: 'polygons',
161
+ index: 3,
162
+ },
163
+ {
164
+ radius: 50,
165
+ x: 300,
166
+ y: 150,
167
+ group: 'circles',
168
+ index: 4,
169
+ },
170
+ ];
171
+
172
+ const shapesMap = {
173
+ rectangles: [
174
+ {
175
+ height: 100,
176
+ width: 100,
177
+ x: 1,
178
+ y: 1,
179
+ index: 0,
180
+ },
181
+ {
182
+ height: 200,
183
+ width: 200,
184
+ x: 200,
185
+ y: 1,
186
+ index: 1,
187
+ },
188
+ ],
189
+ polygons: [
190
+ {
191
+ points: [
192
+ { x: 1, y: 200 },
193
+ { x: 1, y: 200 },
194
+ { y: 200, x: 200 },
195
+ { y: 200, x: 200 },
196
+ ],
197
+ index: 2,
198
+ },
199
+ {
200
+ points: [
201
+ { x: 200, y: 100 },
202
+ { x: 200, y: 200 },
203
+ { x: 400, y: 200 },
204
+ { x: 400, y: 200 },
205
+ ],
206
+ index: 3,
207
+ },
208
+ ],
209
+ circles: [
210
+ {
211
+ radius: 50,
212
+ x: 300,
213
+ y: 150,
214
+ index: 4,
215
+ },
216
+ ],
217
+ };
218
+
219
+ describe('getAllShapes', () => {
220
+ it.each`
221
+ shapesMap | expected
222
+ ${shapesMap} | ${shapesArray}
223
+ ${null} | ${[]}
224
+ ${undefined} | ${[]}
225
+ ${{}} | ${[]}
226
+ `('TURNS shapes = $shapesMap INTO $expected', async ({ shapesMap, expected }) => {
227
+ expect(getAllShapes(shapesMap)).toEqual(expected);
228
+ });
229
+ });
230
+
231
+ describe('groupShapes', () => {
232
+ it.each`
233
+ shapesArray | expected
234
+ ${shapesArray} | ${shapesMap}
235
+ ${null} | ${{ rectangles: [], polygons: [], circles: [] }}
236
+ ${undefined} | ${{ rectangles: [], polygons: [], circles: [] }}
237
+ ${[]} | ${{ rectangles: [], polygons: [], circles: [] }}
238
+ `('TURNS shapes = $shapesArray INTO $expected', async ({ shapesArray, expected }) => {
239
+ expect(groupShapes(shapesArray)).toEqual(expected);
240
+ });
241
+ });
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { styled } from '@mui/material/styles';
4
+ import Button from '@mui/material/Button';
5
+
6
+ const StyledButton = styled(Button)(({ theme }) => ({
7
+ marginLeft: theme.spacing(1),
8
+ }));
9
+
10
+ const RawButton = ({ className, label, onClick, disabled }) => (
11
+ <StyledButton
12
+ onClick={onClick}
13
+ disabled={disabled}
14
+ className={className}
15
+ size="small"
16
+ variant="contained">
17
+ {label}
18
+ </StyledButton>
19
+ );
20
+
21
+ RawButton.propTypes = {
22
+ className: PropTypes.string,
23
+ disabled: PropTypes.bool,
24
+ label: PropTypes.string,
25
+ onClick: PropTypes.func,
26
+ };
27
+
28
+ RawButton.defaultProps = {
29
+ className: '',
30
+ disabled: false,
31
+ label: 'Add',
32
+ onClick: () => {},
33
+ };
34
+
35
+ export default RawButton;
@@ -0,0 +1,18 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+
4
+ export const CircleButton = ({ isActive = false }) => (
5
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" viewBox="56 0 48 32" fill="none">
6
+ <path
7
+ fillRule="evenodd"
8
+ clipRule="evenodd"
9
+ d="M56 4C56 1.79086 57.7909 0 60 0H99C101.209 0 103 1.79086 103 4V28.0001C103 30.2093 101.209 32.0001 99 32.0001H60C57.7909 32.0001 56 30.2093 56 28.0001V4Z"
10
+ fill={isActive ? '#D3D4D9' : '#ECEDF1'}
11
+ />
12
+ <circle cx="79" cy="16" r="7.5" stroke="black" />
13
+ </svg>
14
+ );
15
+
16
+ CircleButton.propTypes = {
17
+ isActive: PropTypes.bool,
18
+ };