@scaleflex/widget-webcam 0.0.1

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.
package/lib/index.js ADDED
@@ -0,0 +1,527 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
5
+ function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
6
+ function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
7
+ function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
8
+ function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
9
+ function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
10
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
11
+ function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
12
+ function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
13
+ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
14
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
15
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
16
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
17
+ import { Plugin } from '@scaleflex/widget-core';
18
+ import Explorer from '@scaleflex/widget-explorer';
19
+ import Translator from '@scaleflex/widget-utils/lib/Translator';
20
+ import getFileTypeExtension from '@scaleflex/widget-utils/lib/getFileTypeExtension';
21
+ import mimeTypes from '@scaleflex/widget-utils/lib/mimeTypes';
22
+ import canvasToBlob from '@scaleflex/widget-utils/lib/canvasToBlob';
23
+ import { PLUGINS_IDS } from '@scaleflex/widget-utils/lib/constants';
24
+ import { CameraIcon } from '@scaleflex/widget-icons/lib';
25
+ import supportsMediaRecorder from './supportsMediaRecorder';
26
+ import CameraScreen from './CameraScreen';
27
+ import PermissionsScreen from './PermissionsScreen';
28
+ import defaultLocale from './defaultLocale';
29
+ import webcamReducer, { webcamCommonStateUpdated } from './common.slice';
30
+ // TODO: find a way to show version of the current plugin
31
+ // why solution below isn't good?
32
+ // first import doesn't work with webpack 5 as it was deprecated
33
+ // second import fixes webpack 5 issue as it was mentioned in their docs
34
+ // but it exposes our package.json to the client and it is mentioned as security rist in mutiple places
35
+ // https://github.com/axelpale/genversion
36
+ // https://stackoverflow.com/questions/64993118/error-should-not-import-the-named-export-version-imported-as-version
37
+ // https://stackoverflow.com/questions/9153571/is-there-a-way-to-get-version-from-package-json-in-nodejs-code/10855054#10855054
38
+ // import { version } from '../package.json'
39
+ // import packageInfo from '../package.json'
40
+
41
+ /**
42
+ * Normalize a MIME type or file extension into a MIME type.
43
+ *
44
+ * @param {string} fileType - MIME type or a file extension prefixed with `.`.
45
+ * @returns {string|undefined} The MIME type or `undefined` if the fileType is an extension and is not known.
46
+ */
47
+ import { jsx as _jsx } from "react/jsx-runtime";
48
+ function toMimeType(fileType) {
49
+ if (fileType[0] === '.') {
50
+ return mimeTypes[fileType.slice(1)];
51
+ }
52
+ return fileType;
53
+ }
54
+
55
+ /**
56
+ * Is this MIME type a video?
57
+ *
58
+ * @param {string} mimeType - MIME type.
59
+ * @returns {boolean}
60
+ */
61
+ function isVideoMimeType(mimeType) {
62
+ return /^video\/[^*]+$/.test(mimeType);
63
+ }
64
+
65
+ /**
66
+ * Is this MIME type an image?
67
+ *
68
+ * @param {string} mimeType - MIME type.
69
+ * @returns {boolean}
70
+ */
71
+ function isImageMimeType(mimeType) {
72
+ return /^image\/[^*]+$/.test(mimeType);
73
+ }
74
+
75
+ /**
76
+ * Setup getUserMedia, with polyfill for older browsers
77
+ * Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
78
+ */
79
+ function getMediaDevices() {
80
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
81
+ return navigator.mediaDevices;
82
+ }
83
+ var _getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
84
+ if (!_getUserMedia) {
85
+ return null;
86
+ }
87
+ return {
88
+ getUserMedia: function getUserMedia(opts) {
89
+ return new Promise(function (resolve, reject) {
90
+ _getUserMedia.call(navigator, opts, resolve, reject);
91
+ });
92
+ }
93
+ };
94
+ }
95
+ /**
96
+ * Webcam
97
+ */
98
+ var Webcam = /*#__PURE__*/function (_Plugin) {
99
+ // static VERSION = packageInfo.version
100
+
101
+ function Webcam(filerobot) {
102
+ var _this;
103
+ var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
104
+ _classCallCheck(this, Webcam);
105
+ _this = _callSuper(this, Webcam, [filerobot, opts]);
106
+ _defineProperty(_this, "_clearRecordingTimer", function () {
107
+ if (_this.opts.showRecordingLength) {
108
+ // Stop the recordingLengthTimer if we are showing the recording length.
109
+ clearInterval(_this.recordingLengthTimer);
110
+ _this.setPluginCommonState({
111
+ recordingLengthSeconds: 0
112
+ });
113
+ }
114
+ });
115
+ _this.mediaDevices = getMediaDevices();
116
+ _this.supportsUserMedia = !!_this.mediaDevices;
117
+ _this.protocol = location.protocol.match(/https/i) ? 'https' : 'http';
118
+ _this.id = PLUGINS_IDS.WEBCAM;
119
+ _this.title = _this.opts.title || 'Camera';
120
+ _this.type = 'acquirer';
121
+ _this.icon = CameraIcon;
122
+ _this.defaultLocale = {
123
+ strings: defaultLocale
124
+ };
125
+
126
+ // set default options
127
+ var defaultOptions = {
128
+ onBeforeSnapshot: function onBeforeSnapshot() {
129
+ return Promise.resolve();
130
+ },
131
+ countdown: false,
132
+ modes: ['video-audio', 'video-only', 'audio-only', 'picture'],
133
+ mirror: true,
134
+ facingMode: 'user',
135
+ preferredImageMimeType: 'image/jpeg',
136
+ preferredVideoMimeType: null,
137
+ showRecordingLength: true,
138
+ isRecordIconHidden: false
139
+ };
140
+ _this.opts = _objectSpread(_objectSpread({}, defaultOptions), opts);
141
+ _this.i18nInit();
142
+ _this.install = _this.install.bind(_this);
143
+ _this.render = _this.render.bind(_this);
144
+
145
+ // Camera controls
146
+ _this._start = _this._start.bind(_this);
147
+ _this._stop = _this._stop.bind(_this);
148
+ _this._takeSnapshot = _this._takeSnapshot.bind(_this);
149
+ _this._startRecording = _this._startRecording.bind(_this);
150
+ _this._stopRecording = _this._stopRecording.bind(_this);
151
+ _this._oneTwoThreeSmile = _this._oneTwoThreeSmile.bind(_this);
152
+ _this._focus = _this._focus.bind(_this);
153
+ _this.webcamActive = false;
154
+ if (_this.opts.countdown) {
155
+ _this.opts.onBeforeSnapshot = _this._oneTwoThreeSmile;
156
+ }
157
+ return _this;
158
+ }
159
+ _inherits(Webcam, _Plugin);
160
+ return _createClass(Webcam, [{
161
+ key: "i18nInit",
162
+ value: function i18nInit() {
163
+ this.translator = new Translator([this.defaultLocale, this.filerobot.locale, this.opts.locale]);
164
+ this.i18n = this.translator.translate.bind(this.translator);
165
+ this.i18nArray = this.translator.translateArray.bind(this.translator);
166
+ }
167
+ }, {
168
+ key: "setPluginCommonState",
169
+ value: function setPluginCommonState(update) {
170
+ return this.dispatch(webcamCommonStateUpdated(update));
171
+ }
172
+ }, {
173
+ key: "getPluginReducer",
174
+ value: function getPluginReducer() {
175
+ return webcamReducer;
176
+ }
177
+ }, {
178
+ key: "hasCameraCheck",
179
+ value: function hasCameraCheck() {
180
+ if (!this.mediaDevices) {
181
+ return Promise.resolve(false);
182
+ }
183
+ return this.mediaDevices.enumerateDevices().then(function (devices) {
184
+ return devices.some(function (device) {
185
+ return device.kind === 'videoinput';
186
+ });
187
+ });
188
+ }
189
+ }, {
190
+ key: "getConstraints",
191
+ value: function getConstraints() {
192
+ var acceptsAudio = this.opts.modes.indexOf('video-audio') !== -1 || this.opts.modes.indexOf('audio-only') !== -1;
193
+ var acceptsVideo = this.opts.modes.indexOf('video-audio') !== -1 || this.opts.modes.indexOf('video-only') !== -1 || this.opts.modes.indexOf('picture') !== -1;
194
+ return {
195
+ audio: acceptsAudio,
196
+ video: acceptsVideo ? {
197
+ facingMode: this.opts.facingMode
198
+ } : false
199
+ };
200
+ }
201
+ }, {
202
+ key: "_start",
203
+ value: function _start() {
204
+ var _this2 = this;
205
+ if (!this.supportsUserMedia) {
206
+ return Promise.reject(new Error('Webcam access not supported'));
207
+ }
208
+ this.webcamActive = true;
209
+ var constraints = this.getConstraints();
210
+ this.hasCameraCheck().then(function (hasCamera) {
211
+ _this2.setPluginCommonState({
212
+ hasCamera: hasCamera
213
+ });
214
+
215
+ // ask user for access to their camera
216
+ return _this2.mediaDevices.getUserMedia(constraints).then(function (stream) {
217
+ _this2.stream = stream;
218
+ _this2.setPluginCommonState({
219
+ cameraReady: true
220
+ });
221
+ })["catch"](function (err) {
222
+ _this2.setPluginCommonState({
223
+ cameraError: err
224
+ });
225
+ });
226
+ });
227
+ }
228
+
229
+ /**
230
+ * @returns {object}
231
+ */
232
+ }, {
233
+ key: "_getMediaRecorderOptions",
234
+ value: function _getMediaRecorderOptions() {
235
+ var options = {};
236
+
237
+ // Try to use the `opts.preferredVideoMimeType` or one of the `allowedFileTypes` for the recording.
238
+ // If the browser doesn't support it, we'll fall back to the browser default instead.
239
+ // Safari doesn't have the `isTypeSupported` API.
240
+ if (MediaRecorder.isTypeSupported) {
241
+ var restrictions = this.filerobot.opts.restrictions;
242
+ var preferredVideoMimeTypes = [];
243
+ if (this.opts.preferredVideoMimeType) {
244
+ preferredVideoMimeTypes = [this.opts.preferredVideoMimeType];
245
+ } else if (restrictions.allowedFileTypes) {
246
+ preferredVideoMimeTypes = restrictions.allowedFileTypes.map(toMimeType).filter(isVideoMimeType);
247
+ }
248
+ var acceptableMimeTypes = preferredVideoMimeTypes.filter(function (candidateType) {
249
+ return MediaRecorder.isTypeSupported(candidateType) && getFileTypeExtension(candidateType);
250
+ });
251
+ if (acceptableMimeTypes.length > 0) {
252
+ options.mimeType = acceptableMimeTypes[0];
253
+ }
254
+ }
255
+ return options;
256
+ }
257
+ }, {
258
+ key: "_startRecording",
259
+ value: function _startRecording() {
260
+ var _this3 = this;
261
+ if (!this.stream) {
262
+ this.filerobot.info(this.i18n('webcamWaitFewSecsAndTryInfo'));
263
+ return;
264
+ }
265
+ this.recorder = new MediaRecorder(this.stream, this._getMediaRecorderOptions());
266
+ this.recordingChunks = [];
267
+ var stoppingBecauseOfMaxSize = false;
268
+ this.recorder.addEventListener('dataavailable', function (event) {
269
+ _this3.recordingChunks.push(event.data);
270
+ var restrictions = _this3.filerobot.opts.restrictions;
271
+ if (_this3.recordingChunks.length > 1 && restrictions.maxFileSize != null && !stoppingBecauseOfMaxSize) {
272
+ var totalSize = _this3.recordingChunks.reduce(function (acc, chunk) {
273
+ return acc + chunk.size;
274
+ }, 0);
275
+ // Exclude the initial chunk from the average size calculation because it is likely to be a very small outlier
276
+ var averageChunkSize = (totalSize - _this3.recordingChunks[0].size) / (_this3.recordingChunks.length - 1);
277
+ var expectedEndChunkSize = averageChunkSize * 3;
278
+ var maxSize = Math.max(0, restrictions.maxFileSize - expectedEndChunkSize);
279
+ if (totalSize > maxSize) {
280
+ stoppingBecauseOfMaxSize = true;
281
+ _this3.filerobot.info(_this3.i18n('webcamRecordingStoppedMaxSizeInfo'), 'warning', 4000);
282
+ _this3._stopRecording();
283
+ }
284
+ }
285
+ });
286
+
287
+ // use a "time slice" of 500ms: ondataavailable will be called each 500ms
288
+ // smaller time slices mean we can more accurately check the max file size restriction
289
+ this.recorder.start(500);
290
+ if (this.opts.showRecordingLength) {
291
+ // Start the recordingLengthTimer if we are showing the recording length.
292
+ this.recordingLengthTimer = setInterval(function () {
293
+ var currentRecordingLength = _this3.getPluginCommonState().recordingLengthSeconds;
294
+ _this3.setPluginCommonState({
295
+ recordingLengthSeconds: currentRecordingLength + 1
296
+ });
297
+ }, 1000);
298
+ }
299
+ this.setPluginCommonState({
300
+ isRecording: true
301
+ });
302
+ }
303
+ }, {
304
+ key: "_stopRecording",
305
+ value: function _stopRecording() {
306
+ var _this4 = this;
307
+ var stopped = new Promise(function (resolve, reject) {
308
+ _this4.recorder.addEventListener('stop', function () {
309
+ resolve();
310
+ });
311
+ _this4.recorder.stop();
312
+ _this4._clearRecordingTimer();
313
+ });
314
+ return stopped.then(function () {
315
+ _this4.setPluginCommonState({
316
+ isRecording: false
317
+ });
318
+ return _this4.getVideo();
319
+ }).then(function (file) {
320
+ try {
321
+ _this4.filerobot.addFile(file);
322
+ } catch (err) {
323
+ // Logging the error, exept restrictions, which is handled in Core
324
+ if (!err.isRestriction) {
325
+ _this4.filerobot.log(err);
326
+ }
327
+ }
328
+ }).then(function () {
329
+ _this4.recordingChunks = null;
330
+ _this4.recorder = null;
331
+ }, function (error) {
332
+ _this4.recordingChunks = null;
333
+ _this4.recorder = null;
334
+ throw error;
335
+ });
336
+ }
337
+ }, {
338
+ key: "_stop",
339
+ value: function _stop() {
340
+ if (this.stream) {
341
+ this.stream.getAudioTracks().forEach(function (track) {
342
+ track.stop();
343
+ });
344
+ this.stream.getVideoTracks().forEach(function (track) {
345
+ track.stop();
346
+ });
347
+ }
348
+ if (this.getPluginCommonState().isRecording) {
349
+ this._clearRecordingTimer();
350
+ this.setPluginCommonState({
351
+ isRecording: false
352
+ });
353
+ }
354
+ this.webcamActive = false;
355
+ this.stream = null;
356
+ }
357
+ }, {
358
+ key: "_getVideoElement",
359
+ value: function _getVideoElement() {
360
+ return document.body.querySelector('.filerobot-Webcam-video');
361
+ }
362
+ }, {
363
+ key: "_oneTwoThreeSmile",
364
+ value: function _oneTwoThreeSmile() {
365
+ var _this5 = this;
366
+ return new Promise(function (resolve, reject) {
367
+ var count = _this5.opts.countdown;
368
+ var countDown = setInterval(function () {
369
+ if (!_this5.webcamActive) {
370
+ clearInterval(countDown);
371
+ _this5.captureInProgress = false;
372
+ return reject(new Error('Webcam is not active'));
373
+ }
374
+ if (count > 0) {
375
+ _this5.filerobot.info("".concat(count, "..."), 'warning', 800);
376
+ count--;
377
+ } else {
378
+ clearInterval(countDown);
379
+ _this5.filerobot.info(_this5.i18n('webcamSmileInfo'), 'success', 1500);
380
+ setTimeout(function () {
381
+ return resolve();
382
+ }, 1500);
383
+ }
384
+ }, 1000);
385
+ });
386
+ }
387
+ }, {
388
+ key: "_takeSnapshot",
389
+ value: function _takeSnapshot() {
390
+ var _this6 = this;
391
+ if (this.captureInProgress) return;
392
+ this.captureInProgress = true;
393
+ this.opts.onBeforeSnapshot()["catch"](function (err) {
394
+ var message = _typeof(err) === 'object' ? err.message : err;
395
+ _this6.filerobot.info(message, 'error', 5000);
396
+ return Promise.reject(new Error("onBeforeSnapshot: ".concat(message)));
397
+ }).then(function () {
398
+ return _this6._getImage();
399
+ }).then(function (tagFile) {
400
+ _this6.captureInProgress = false;
401
+ try {
402
+ _this6.filerobot.addFile(tagFile);
403
+ } catch (err) {
404
+ // Logging the error, except restrictions, which is handled in Core
405
+ if (!err.isRestriction) {
406
+ _this6.filerobot.log(err);
407
+ }
408
+ }
409
+ }, function (error) {
410
+ _this6.captureInProgress = false;
411
+ throw error;
412
+ });
413
+ }
414
+ }, {
415
+ key: "_getImage",
416
+ value: function _getImage() {
417
+ var _this7 = this;
418
+ var video = this._getVideoElement();
419
+ if (!video) {
420
+ return Promise.reject(new Error('No video element found, likely due to the Webcam tab being closed.'));
421
+ }
422
+ var width = video.videoWidth;
423
+ var height = video.videoHeight;
424
+ var canvas = document.createElement('canvas');
425
+ canvas.width = width;
426
+ canvas.height = height;
427
+ var ctx = canvas.getContext('2d');
428
+ ctx.drawImage(video, 0, 0);
429
+ var restrictions = this.filerobot.opts.restrictions;
430
+ var preferredImageMimeTypes = [];
431
+ if (this.opts.preferredImageMimeType) {
432
+ preferredImageMimeTypes = [this.opts.preferredImageMimeType];
433
+ } else if (restrictions.allowedFileTypes) {
434
+ preferredImageMimeTypes = restrictions.allowedFileTypes.map(toMimeType).filter(isImageMimeType);
435
+ }
436
+ var mimeType = preferredImageMimeTypes[0] || 'image/jpeg';
437
+ var ext = getFileTypeExtension(mimeType) || 'jpg';
438
+ var name = "cam-".concat(Date.now(), ".").concat(ext);
439
+ return canvasToBlob(canvas, mimeType).then(function (blob) {
440
+ return {
441
+ source: _this7.id,
442
+ name: name,
443
+ data: new Blob([blob], {
444
+ type: mimeType
445
+ }),
446
+ type: mimeType
447
+ };
448
+ });
449
+ }
450
+ }, {
451
+ key: "getVideo",
452
+ value: function getVideo() {
453
+ var mimeType = this.recordingChunks[0].type;
454
+ var fileExtension = getFileTypeExtension(mimeType);
455
+ if (!fileExtension) {
456
+ return Promise.reject(new Error("Could not retrieve recording: Unsupported media type \"".concat(mimeType, "\"")));
457
+ }
458
+ var name = "webcam-".concat(Date.now(), ".").concat(fileExtension);
459
+ var blob = new Blob(this.recordingChunks, {
460
+ type: mimeType
461
+ });
462
+ var file = {
463
+ source: this.id,
464
+ name: name,
465
+ data: new Blob([blob], {
466
+ type: mimeType
467
+ }),
468
+ type: mimeType
469
+ };
470
+ return Promise.resolve(file);
471
+ }
472
+ }, {
473
+ key: "_focus",
474
+ value: function _focus() {
475
+ var _this8 = this;
476
+ if (!this.opts.countdown) return;
477
+ setTimeout(function () {
478
+ _this8.filerobot.info(_this8.i18n('webcamSmileInfo'), 'success', 1500);
479
+ }, 1000);
480
+ }
481
+ }, {
482
+ key: "render",
483
+ value: function render() {
484
+ if (!this.webcamActive) {
485
+ this._start();
486
+ }
487
+ var webcamState = this.getPluginCommonState();
488
+ if (!webcamState.cameraReady || !webcamState.hasCamera) {
489
+ return /*#__PURE__*/_jsx(PermissionsScreen, {
490
+ i18n: this.i18n,
491
+ hasCamera: webcamState.hasCamera
492
+ });
493
+ }
494
+ return /*#__PURE__*/_jsx(CameraScreen, {
495
+ onSnapshot: this._takeSnapshot,
496
+ onStartRecording: this._startRecording,
497
+ onStopRecording: this._stopRecording,
498
+ onFocus: this._focus,
499
+ onStop: this._stop,
500
+ modes: this.opts.modes,
501
+ showRecordingLength: this.opts.showRecordingLength,
502
+ supportsRecording: supportsMediaRecorder(),
503
+ isRecording: webcamState.isRecording,
504
+ recordingLengthSeconds: webcamState.recordingLengthSeconds,
505
+ mirror: this.opts.mirror,
506
+ src: this.stream,
507
+ isRecordIconHidden: this.opts.isRecordIconHidden
508
+ });
509
+ }
510
+ }, {
511
+ key: "install",
512
+ value: function install() {
513
+ if (Explorer) {
514
+ this.mount(Explorer, this);
515
+ }
516
+ }
517
+ }, {
518
+ key: "uninstall",
519
+ value: function uninstall() {
520
+ if (this.stream) {
521
+ this._stop();
522
+ }
523
+ this.unmount();
524
+ }
525
+ }]);
526
+ }(Plugin);
527
+ export { Webcam as default };
@@ -0,0 +1,3 @@
1
+ export default function supportsMediaRecorder() {
2
+ return typeof MediaRecorder === 'function' && !!MediaRecorder.prototype && typeof MediaRecorder.prototype.start === 'function';
3
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@scaleflex/widget-webcam",
3
+ "description": "Scaleflex plugin that takes photos or records videos using the device's camera.",
4
+ "version": "0.0.1",
5
+ "license": "MIT",
6
+ "main": "lib/index.js",
7
+ "style": "dist/style.min.css",
8
+ "types": "types/index.d.ts",
9
+ "dependencies": {
10
+ "@scaleflex/widget-common": "^0.0.1",
11
+ "@scaleflex/widget-icons": "^0.0.1",
12
+ "@scaleflex/widget-utils": "^0.0.1"
13
+ },
14
+ "devDependencies": {
15
+ "react": "^19.0.0",
16
+ "react-dom": "^19.0.0"
17
+ },
18
+ "peerDependencies": {
19
+ "@scaleflex/widget-core": "^0.0.0",
20
+ "@scaleflex/widget-explorer": "^0.0.0",
21
+ "react": ">=19.0.0",
22
+ "react-dom": ">=19.0.0"
23
+ },
24
+ "files": [
25
+ "/dist",
26
+ "/lib",
27
+ "/types"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "gitHead": "64ea82e745b7deda36d6794863350e6671e9010d"
33
+ }
@@ -0,0 +1,25 @@
1
+ import Filerobot = require("@scaleflex/widget-core");
2
+ import WebcamLocale = require("./generatedLocale");
3
+
4
+ declare module Webcam {
5
+ export type WebcamMode =
6
+ | "video-audio"
7
+ | "video-only"
8
+ | "audio-only"
9
+ | "picture";
10
+
11
+ export interface WebcamOptions extends Filerobot.PluginOptions {
12
+ replaceTargetContent?: boolean;
13
+ target?: Filerobot.PluginTarget;
14
+ onBeforeSnapshot?: () => Promise<void>;
15
+ countdown?: number | boolean;
16
+ mirror?: boolean;
17
+ facingMode?: string;
18
+ modes?: WebcamMode[];
19
+ locale?: WebcamLocale;
20
+ }
21
+ }
22
+
23
+ declare class Webcam extends Filerobot.Plugin<Webcam.WebcamOptions> {}
24
+
25
+ export = Webcam;