scandit-datacapture-frameworks-core 8.2.1 → 8.3.0

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 (37) hide show
  1. package/__mocks__/Defaults.ts +6 -1
  2. package/dist/dts/ClusteringMode.d.ts +6 -0
  3. package/dist/dts/camera/Camera.d.ts +16 -3
  4. package/dist/dts/camera/CameraSettings.d.ts +10 -3
  5. package/dist/dts/camera/FocusGesture.d.ts +6 -0
  6. package/dist/dts/camera/FocusGestureListener.d.ts +5 -0
  7. package/dist/dts/camera/FocusGestureListenerEvents.d.ts +3 -0
  8. package/dist/dts/camera/MacroMode.d.ts +5 -0
  9. package/dist/dts/camera/SwipeToZoom.d.ts +14 -0
  10. package/dist/dts/camera/TapToFocus.d.ts +15 -0
  11. package/dist/dts/camera/TorchSwitchControl.d.ts +5 -0
  12. package/dist/dts/camera/ZoomGesture.d.ts +5 -0
  13. package/dist/dts/camera/ZoomGestureListener.d.ts +5 -0
  14. package/dist/dts/camera/ZoomGestureListenerEvents.d.ts +4 -0
  15. package/dist/dts/camera/ZoomSwitchControl.d.ts +7 -0
  16. package/dist/dts/camera/controller/CameraController.d.ts +8 -0
  17. package/dist/dts/camera/index.d.ts +5 -0
  18. package/dist/dts/camerahelpers/MacroModeListenerEvents.d.ts +3 -0
  19. package/dist/dts/camerahelpers/TorchListenerEvents.d.ts +3 -0
  20. package/dist/dts/camerahelpers/index.d.ts +2 -0
  21. package/dist/dts/common/Color.d.ts +1 -1
  22. package/dist/dts/common/Payload.d.ts +36 -1
  23. package/dist/dts/defaults/CoreDefaults.d.ts +7 -1
  24. package/dist/dts/defaults/getCoreDefaults.d.ts +1 -1
  25. package/dist/dts/frame/FrameData.d.ts +6 -0
  26. package/dist/dts/frame/MacroModeListener.d.ts +4 -0
  27. package/dist/dts/frame/TorchListener.d.ts +4 -0
  28. package/dist/dts/frame/index.d.ts +2 -0
  29. package/dist/dts/generated/CoreProxyAdapter.d.ts +71 -0
  30. package/dist/dts/index.d.ts +1 -0
  31. package/dist/dts/view/DataCaptureView.d.ts +7 -0
  32. package/dist/dts/view/DataCaptureViewController.d.ts +22 -2
  33. package/dist/index.js +871 -69
  34. package/dist/index.js.map +1 -1
  35. package/package.json +3 -3
  36. package/test/CameraSettings.test.ts +335 -0
  37. package/test/Color.test.ts +98 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scandit-datacapture-frameworks-core",
3
- "version": "8.2.1",
3
+ "version": "8.3.0",
4
4
  "description": "Core common package",
5
5
  "author": {
6
6
  "name": "Scandit",
@@ -10,10 +10,10 @@
10
10
  "main": "dist/index.js",
11
11
  "types": "dist/dts/index.d.ts",
12
12
  "scripts": {
13
- "build": "rollup -c rollup.config.js --bundleConfigAsCjs",
13
+ "build": "rollup -c ../../../rollup.config.js --bundleConfigAsCjs",
14
14
  "clean": "rimraf .rollup.cache dist",
15
15
  "lint": "eslint ./src",
16
- "prepack": "pnpm run build",
16
+ "prepack": "rollup -c ../../../rollup.config.js --bundleConfigAsCjs",
17
17
  "test": "jest --passWithNoTests",
18
18
  "coverage": "jest --coverage --passWithNoTests"
19
19
  },
@@ -0,0 +1,335 @@
1
+ import { describe, it, expect, beforeEach } from '@jest/globals';
2
+ import { CameraSettings } from '../src';
3
+ import { parseDefaults } from '../src/defaults/CoreDefaults';
4
+ import { FocusRange } from '../src/camera/FocusRange';
5
+ import { FocusGestureStrategy } from '../src/camera/FocusGestureStrategy';
6
+ import { VideoResolution } from '../src/camera/VideoResolution';
7
+ import { MacroMode } from '../src/camera/MacroMode';
8
+ import { loadMockDefaults, mockCoreDefaultsData } from '../__mocks__/Defaults';
9
+
10
+ beforeEach(() => {
11
+ loadMockDefaults();
12
+ });
13
+
14
+ describe('CameraSettings', () => {
15
+
16
+ describe('default constructor', () => {
17
+ it('initializes all fields from mock defaults', () => {
18
+ const settings = new CameraSettings();
19
+
20
+ expect(settings.preferredResolution).toBe(VideoResolution.Auto);
21
+ expect(settings.zoomFactor).toBe(1);
22
+ expect(settings.zoomGestureZoomFactor).toBe(2);
23
+ expect(settings.torchLevel).toBe(1);
24
+ expect(settings.macroMode).toBe('auto');
25
+ expect(settings.adaptiveExposure).toBe(false);
26
+ });
27
+
28
+ it('initializes focus sub-fields via getProperty', () => {
29
+ const settings = new CameraSettings();
30
+
31
+ expect(settings.focusRange).toBe('near');
32
+ expect(settings.focusGestureStrategy).toBe('manualUntilCapture');
33
+ expect(settings.shouldPreferSmoothAutoFocus).toBe(false);
34
+ // manualLensPosition and focusStrategy are optional — undefined until explicitly set
35
+ expect(settings.getProperty('manualLensPosition')).toBeUndefined();
36
+ expect(settings.getProperty('focusStrategy')).toBeUndefined();
37
+ });
38
+ });
39
+
40
+ describe('fromJSON — native format (flat top-level + properties bag)', () => {
41
+ // This is what Android and iOS actually send.
42
+ // Focus basics (focusRange, focusGestureStrategy, shouldPreferSmoothAutoFocus) are
43
+ // at the top level. manualLensPosition and focusStrategy come in the properties bag.
44
+ // iOS additionally sends "range" in properties (same value as focusRange).
45
+ it('deserializes top-level focus fields and properties bag', () => {
46
+ const json = {
47
+ preferredResolution: 'fullHd',
48
+ zoomFactor: 1.5,
49
+ zoomGestureZoomFactor: 3,
50
+ focusRange: 'full',
51
+ focusGestureStrategy: 'autoFocus',
52
+ shouldPreferSmoothAutoFocus: true,
53
+ macroMode: 'disabled',
54
+ adaptiveExposure: true,
55
+ torchLevel: 0.8,
56
+ properties: {
57
+ range: 'full', // iOS sends this (same as focusRange)
58
+ manualLensPosition: 0.5,
59
+ focusStrategy: 'autoFocus',
60
+ overwriteWithHighestResolution: true,
61
+ },
62
+ };
63
+
64
+ const settings = (CameraSettings as any).fromJSON(json);
65
+
66
+ expect(settings.preferredResolution).toBe('fullHd');
67
+ expect(settings.zoomFactor).toBe(1.5);
68
+ expect(settings.zoomGestureZoomFactor).toBe(3);
69
+ expect(settings.macroMode).toBe('disabled');
70
+ expect(settings.adaptiveExposure).toBe(true);
71
+ expect(settings.torchLevel).toBe(0.8);
72
+
73
+ // All focus properties end up in the focus bag
74
+ expect(settings.focusRange).toBe('full');
75
+ expect(settings.focusGestureStrategy).toBe('autoFocus');
76
+ expect(settings.shouldPreferSmoothAutoFocus).toBe(true);
77
+ expect(settings.getProperty('range')).toBe('full');
78
+ expect(settings.getProperty('manualLensPosition')).toBe(0.5);
79
+ expect(settings.getProperty('focusStrategy')).toBe('autoFocus');
80
+ // Non-focus property goes to top-level field
81
+ expect(settings.getProperty('overwriteWithHighestResolution')).toBe(true);
82
+ });
83
+
84
+ it('focus properties from properties bag all route to the focus bag', () => {
85
+ const json = {
86
+ preferredResolution: 'auto',
87
+ zoomFactor: 1,
88
+ zoomGestureZoomFactor: 2,
89
+ properties: {
90
+ range: 'near',
91
+ manualLensPosition: 0.3,
92
+ focusStrategy: 'onlyOnRequest',
93
+ focusGestureStrategy: 'manualUntilCapture',
94
+ shouldPreferSmoothAutoFocus: false,
95
+ },
96
+ };
97
+
98
+ const settings = (CameraSettings as any).fromJSON(json);
99
+
100
+ // All focusHiddenProperties members routed to focus bag regardless of source
101
+ expect(settings.getProperty('range')).toBe('near');
102
+ expect(settings.focusRange).toBe('near');
103
+ expect(settings.getProperty('manualLensPosition')).toBe(0.3);
104
+ expect(settings.getProperty('focusStrategy')).toBe('onlyOnRequest');
105
+ expect(settings.getProperty('focusGestureStrategy')).toBe('manualUntilCapture');
106
+ expect(settings.focusGestureStrategy).toBe('manualUntilCapture');
107
+ expect(settings.getProperty('shouldPreferSmoothAutoFocus')).toBe(false);
108
+ expect(settings.shouldPreferSmoothAutoFocus).toBe(false);
109
+ });
110
+ });
111
+
112
+ describe('fromJSON — Android format (no range in properties)', () => {
113
+ // Android CameraSettingsPropertiesDefaults does NOT include "range" in the properties bag.
114
+ // Only manualLensPosition and focusStrategy are sent. focus.range must come from
115
+ // the top-level focusRange field, and getProperty('range') must stay consistent.
116
+ it('sets focus.range from top-level focusRange when range is absent from properties', () => {
117
+ const json = {
118
+ preferredResolution: 'auto',
119
+ zoomFactor: 1,
120
+ zoomGestureZoomFactor: 2,
121
+ focusRange: 'full',
122
+ focusGestureStrategy: 'manualUntilCapture',
123
+ shouldPreferSmoothAutoFocus: false,
124
+ macroMode: 'auto',
125
+ adaptiveExposure: false,
126
+ torchLevel: 1,
127
+ properties: {
128
+ manualLensPosition: 0.2,
129
+ focusStrategy: 'onlyOnRequest',
130
+ // no "range" key — Android does not send it
131
+ },
132
+ };
133
+
134
+ const settings = (CameraSettings as any).fromJSON(json);
135
+
136
+ expect(settings.focusRange).toBe('full');
137
+ // getProperty('range') reads from the same focus bag as focusRange
138
+ expect(settings.getProperty('range')).toBe('full');
139
+ expect(settings.getProperty('manualLensPosition')).toBe(0.2);
140
+ expect(settings.getProperty('focusStrategy')).toBe('onlyOnRequest');
141
+ });
142
+ });
143
+
144
+ describe('fromJSON — sparse properties bag (null-filtered by native)', () => {
145
+ // Both Android and iOS filter null values from the properties bag before sending.
146
+ // When manualLensPosition or focusStrategy are null on the native side, they are
147
+ // absent from properties entirely. The TS side must fall back to coreDefaults.
148
+ it('leaves manualLensPosition and focusStrategy as undefined when absent from properties', () => {
149
+ const json = {
150
+ preferredResolution: 'auto',
151
+ zoomFactor: 1,
152
+ zoomGestureZoomFactor: 2,
153
+ properties: {
154
+ // manualLensPosition and focusStrategy absent (filtered as null by native)
155
+ overwriteWithHighestResolution: false,
156
+ },
157
+ };
158
+
159
+ const settings = (CameraSettings as any).fromJSON(json);
160
+
161
+ // Not present in properties bag — remain undefined (not defaulted from coreDefaults)
162
+ expect(settings.getProperty('manualLensPosition')).toBeUndefined();
163
+ expect(settings.getProperty('focusStrategy')).toBeUndefined();
164
+ });
165
+
166
+ it('leaves focus basics as undefined when top-level focus fields are absent from JSON', () => {
167
+ // In practice native always sends these fields, but when absent fromJSON does not
168
+ // fall back to defaults — callers are expected to provide them.
169
+ const json = {
170
+ preferredResolution: 'auto',
171
+ zoomFactor: 1,
172
+ zoomGestureZoomFactor: 2,
173
+ properties: {},
174
+ };
175
+
176
+ const settings = (CameraSettings as any).fromJSON(json);
177
+
178
+ expect(settings.focusRange).toBeUndefined();
179
+ expect(settings.focusGestureStrategy).toBeUndefined();
180
+ expect(settings.shouldPreferSmoothAutoFocus).toBeUndefined();
181
+ });
182
+ });
183
+
184
+ describe('parseDefaults — new fields with fallbacks', () => {
185
+ // parseDefaults (CoreDefaults.ts) applies hardcoded fallbacks for fields introduced
186
+ // after the initial release. Older native builds may omit torchLevel, macroMode,
187
+ // adaptiveExposure, manualLensPosition, focusStrategy from the defaults JSON.
188
+ // Tested via parseDefaults directly since loadCoreDefaults uses bindInstanceIfNotExists
189
+ // and won't replace already-loaded defaults.
190
+ it('uses hardcoded fallbacks when new fields are absent from native defaults JSON', () => {
191
+ // Build from the full mock so parseDefaults has all the sections it needs,
192
+ // then strip the new Camera.Settings fields to simulate an older native build.
193
+ const { torchLevel, macroMode, adaptiveExposure, manualLensPosition, focusStrategy, ...oldSettings } =
194
+ mockCoreDefaultsData.Camera.Settings;
195
+ const oldNativeData = {
196
+ ...mockCoreDefaultsData,
197
+ Camera: { ...mockCoreDefaultsData.Camera, Settings: oldSettings },
198
+ };
199
+
200
+ const defaults = parseDefaults(oldNativeData);
201
+
202
+ expect(defaults.Camera.Settings.torchLevel).toBe(1.0); // ?? 1.0
203
+ expect(defaults.Camera.Settings.macroMode).toBe('auto'); // ?? 'auto'
204
+ expect(defaults.Camera.Settings.adaptiveExposure).toBe(false); // ?? false
205
+ expect(defaults.Camera.Settings.manualLensPosition).toBe(0); // ?? 0
206
+ expect(defaults.Camera.Settings.focusStrategy).toBe('auto'); // ?? 'auto'
207
+ });
208
+
209
+ it('reads new fields when present in native defaults JSON', () => {
210
+ const newNativeData = {
211
+ ...mockCoreDefaultsData,
212
+ Camera: {
213
+ ...mockCoreDefaultsData.Camera,
214
+ Settings: {
215
+ ...mockCoreDefaultsData.Camera.Settings,
216
+ torchLevel: 0.5,
217
+ macroMode: 'disabled',
218
+ adaptiveExposure: true,
219
+ manualLensPosition: 0.8,
220
+ focusStrategy: 'autoFocus',
221
+ },
222
+ },
223
+ };
224
+
225
+ const defaults = parseDefaults(newNativeData);
226
+
227
+ expect(defaults.Camera.Settings.torchLevel).toBe(0.5);
228
+ expect(defaults.Camera.Settings.macroMode).toBe('disabled');
229
+ expect(defaults.Camera.Settings.adaptiveExposure).toBe(true);
230
+ expect(defaults.Camera.Settings.manualLensPosition).toBe(0.8);
231
+ expect(defaults.Camera.Settings.focusStrategy).toBe('autoFocus');
232
+ });
233
+ });
234
+
235
+ describe('fromJSON — missing optional fields fall back to defaults', () => {
236
+ it('does not crash when focus, properties, and optional fields are all absent', () => {
237
+ const json = {
238
+ preferredResolution: 'auto',
239
+ zoomFactor: 1,
240
+ zoomGestureZoomFactor: 2,
241
+ };
242
+
243
+ expect(() => (CameraSettings as any).fromJSON(json)).not.toThrow();
244
+ });
245
+
246
+ it('uses defaults for macroMode, adaptiveExposure, torchLevel when absent', () => {
247
+ const json = {
248
+ preferredResolution: 'auto',
249
+ zoomFactor: 1,
250
+ zoomGestureZoomFactor: 2,
251
+ };
252
+
253
+ const settings = (CameraSettings as any).fromJSON(json);
254
+
255
+ expect(settings.torchLevel).toBe(1);
256
+ expect(settings.macroMode).toBe('auto');
257
+ expect(settings.adaptiveExposure).toBe(false);
258
+ });
259
+
260
+ it('leaves all focus fields as undefined when both focus object and top-level focus fields are absent', () => {
261
+ const json = {
262
+ preferredResolution: 'auto',
263
+ zoomFactor: 1,
264
+ zoomGestureZoomFactor: 2,
265
+ };
266
+
267
+ const settings = (CameraSettings as any).fromJSON(json);
268
+
269
+ expect(settings.focusRange).toBeUndefined();
270
+ expect(settings.focusGestureStrategy).toBeUndefined();
271
+ expect(settings.shouldPreferSmoothAutoFocus).toBeUndefined();
272
+ expect(settings.getProperty('manualLensPosition')).toBeUndefined();
273
+ expect(settings.getProperty('focusStrategy')).toBeUndefined();
274
+ });
275
+ });
276
+
277
+ describe('setProperty / getProperty', () => {
278
+ it('routes all focusHiddenProperties to the focus bag', () => {
279
+ const settings = new CameraSettings();
280
+
281
+ settings.setProperty('range', 'infinite' as FocusRange);
282
+ settings.setProperty('manualLensPosition', 0.75);
283
+ settings.setProperty('focusStrategy', 'autoFocus');
284
+ settings.setProperty('focusGestureStrategy', 'manual' as FocusGestureStrategy);
285
+ settings.setProperty('shouldPreferSmoothAutoFocus', true);
286
+
287
+ expect(settings.getProperty('range')).toBe('infinite');
288
+ expect(settings.getProperty('manualLensPosition')).toBe(0.75);
289
+ expect(settings.getProperty('focusStrategy')).toBe('autoFocus');
290
+ expect(settings.getProperty('focusGestureStrategy')).toBe('manual');
291
+ expect(settings.getProperty('shouldPreferSmoothAutoFocus')).toBe(true);
292
+
293
+ // Public accessors also reflect the updated values
294
+ expect(settings.focusRange).toBe('infinite');
295
+ expect(settings.focusGestureStrategy).toBe('manual');
296
+ expect(settings.shouldPreferSmoothAutoFocus).toBe(true);
297
+ });
298
+
299
+ it('routes non-focus properties to top-level fields', () => {
300
+ const settings = new CameraSettings();
301
+
302
+ settings.setProperty('zoomFactor', 3.5);
303
+
304
+ expect(settings.getProperty('zoomFactor')).toBe(3.5);
305
+ expect(settings.zoomFactor).toBe(3.5);
306
+ });
307
+ });
308
+
309
+ describe('copy constructor', () => {
310
+ it('copies all settings including focus sub-fields', () => {
311
+ const original = new CameraSettings();
312
+ original.zoomFactor = 2.5;
313
+ original.torchLevel = 0.5;
314
+ original.macroMode = 'disabled' as MacroMode;
315
+ original.adaptiveExposure = true;
316
+ original.focusRange = 'far' as FocusRange;
317
+ original.focusGestureStrategy = 'autoFocus' as FocusGestureStrategy;
318
+ original.shouldPreferSmoothAutoFocus = true;
319
+ original.setProperty('manualLensPosition', 0.3);
320
+ original.setProperty('focusStrategy', 'autoFocus');
321
+
322
+ const copy = new CameraSettings(original);
323
+
324
+ expect(copy.zoomFactor).toBe(2.5);
325
+ expect(copy.torchLevel).toBe(0.5);
326
+ expect(copy.macroMode).toBe('disabled');
327
+ expect(copy.adaptiveExposure).toBe(true);
328
+ expect(copy.focusRange).toBe('far');
329
+ expect(copy.focusGestureStrategy).toBe('autoFocus');
330
+ expect(copy.shouldPreferSmoothAutoFocus).toBe(true);
331
+ expect(copy.getProperty('manualLensPosition')).toBe(0.3);
332
+ expect(copy.getProperty('focusStrategy')).toBe('autoFocus');
333
+ });
334
+ });
335
+ });
@@ -0,0 +1,98 @@
1
+ import { describe, it, expect } from '@jest/globals';
2
+ import { Color } from '../src/common/Color';
3
+
4
+ describe('Color', () => {
5
+ describe('fromHex', () => {
6
+ it('parses a hex string with # prefix correctly', () => {
7
+ const color = Color.fromHex('#FF8040FF');
8
+ expect(color.red).toBe(0xff);
9
+ expect(color.green).toBe(0x80);
10
+ expect(color.blue).toBe(0x40);
11
+ expect(color.alpha).toBe(0xff);
12
+ });
13
+
14
+ it('parses a hex string without # prefix correctly', () => {
15
+ const color = Color.fromHex('FF8040FF');
16
+ expect(color.red).toBe(0xff);
17
+ expect(color.green).toBe(0x80);
18
+ expect(color.blue).toBe(0x40);
19
+ expect(color.alpha).toBe(0xff);
20
+ });
21
+
22
+ it('adds default full alpha when alpha is omitted', () => {
23
+ const color = Color.fromHex('#FF8040');
24
+ expect(color.red).toBe(0xff);
25
+ expect(color.green).toBe(0x80);
26
+ expect(color.blue).toBe(0x40);
27
+ expect(color.alpha).toBe(0xff);
28
+ });
29
+
30
+ it('expands shorthand 3-digit hex', () => {
31
+ const color = Color.fromHex('#F80');
32
+ expect(color.red).toBe(0xff);
33
+ expect(color.green).toBe(0x88);
34
+ expect(color.blue).toBe(0x00);
35
+ expect(color.alpha).toBe(0xff);
36
+ });
37
+ });
38
+
39
+ describe('fromRGBA', () => {
40
+ it('creates color from integer RGBA components', () => {
41
+ const color = Color.fromRGBA(255, 128, 64, 255);
42
+ expect(color.red).toBe(255);
43
+ expect(color.green).toBe(128);
44
+ expect(color.blue).toBe(64);
45
+ expect(color.alpha).toBe(255);
46
+ });
47
+
48
+ it('normalizes fractional alpha in range (0, 1] to 0-255', () => {
49
+ const color = Color.fromRGBA(0, 0, 0, 1.0);
50
+ expect(color.alpha).toBe(255);
51
+ });
52
+
53
+ it('uses full alpha by default', () => {
54
+ const color = Color.fromRGBA(10, 20, 30);
55
+ expect(color.alpha).toBe(255);
56
+ });
57
+ });
58
+
59
+ describe('component accessors return valid numbers', () => {
60
+ it('red is not NaN', () => {
61
+ expect(Color.fromHex('#AABBCCDD').red).not.toBeNaN();
62
+ });
63
+
64
+ it('green is not NaN', () => {
65
+ expect(Color.fromHex('#AABBCCDD').green).not.toBeNaN();
66
+ });
67
+
68
+ it('blue is not NaN', () => {
69
+ expect(Color.fromHex('#AABBCCDD').blue).not.toBeNaN();
70
+ });
71
+
72
+ it('alpha is not NaN', () => {
73
+ expect(Color.fromHex('#AABBCCDD').alpha).not.toBeNaN();
74
+ });
75
+ });
76
+
77
+ describe('withAlpha', () => {
78
+ it('replaces alpha while keeping RGB intact', () => {
79
+ const color = Color.fromHex('#FF8040FF').withAlpha(0.5);
80
+ expect(color.red).toBe(0xff);
81
+ expect(color.green).toBe(0x80);
82
+ expect(color.blue).toBe(0x40);
83
+ expect(color.alpha).toBe(Math.round(255 * 0.5));
84
+ });
85
+ });
86
+
87
+ describe('toJSON', () => {
88
+ it('serializes with a leading # character', () => {
89
+ const color = Color.fromHex('#FF8040FF');
90
+ expect(color.toJSON()).toMatch(/^#/);
91
+ });
92
+
93
+ it('round-trips through fromHex and toJSON', () => {
94
+ const hex = '#FF8040FF';
95
+ expect(Color.fromHex(hex).toJSON()).toBe(hex);
96
+ });
97
+ });
98
+ });