@uploadcare/file-uploader 1.13.0-alpha.1 → 1.13.0-alpha.3

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 (45) hide show
  1. package/abstract/UploaderPublicApi.d.ts.map +1 -1
  2. package/abstract/UploaderPublicApi.js +11 -4
  3. package/blocks/CameraSource/CameraSource.d.ts +22 -12
  4. package/blocks/CameraSource/CameraSource.d.ts.map +1 -1
  5. package/blocks/CameraSource/CameraSource.js +83 -81
  6. package/blocks/CameraSource/camera-source.css +0 -1
  7. package/blocks/CloudImageEditor/src/CropFrame.d.ts +7 -0
  8. package/blocks/CloudImageEditor/src/CropFrame.d.ts.map +1 -1
  9. package/blocks/CloudImageEditor/src/CropFrame.js +50 -0
  10. package/blocks/CloudImageEditor/src/css/common.css +4 -0
  11. package/blocks/CloudImageEditor/src/lib/parseTabs.js +2 -2
  12. package/blocks/Config/Config.d.ts +3 -3
  13. package/blocks/Config/Config.d.ts.map +1 -1
  14. package/blocks/Config/Config.js +3 -13
  15. package/blocks/Config/initialConfig.d.ts.map +1 -1
  16. package/blocks/Config/initialConfig.js +5 -4
  17. package/blocks/Config/normalizeConfigValue.d.ts.map +1 -1
  18. package/blocks/Config/normalizeConfigValue.js +8 -20
  19. package/blocks/utils/comma-separated.d.ts +1 -1
  20. package/blocks/utils/comma-separated.d.ts.map +1 -1
  21. package/blocks/utils/comma-separated.js +2 -5
  22. package/index.ssr.d.ts +14 -0
  23. package/index.ssr.d.ts.map +1 -1
  24. package/index.ssr.js +16 -5
  25. package/package.json +6 -4
  26. package/types/exported.d.ts +66 -81
  27. package/web/file-uploader.iife.min.js +4 -4
  28. package/web/file-uploader.min.js +4 -4
  29. package/web/uc-basic.min.css +1 -1
  30. package/web/uc-cloud-image-editor.min.css +1 -1
  31. package/web/uc-cloud-image-editor.min.js +4 -4
  32. package/web/uc-file-uploader-inline.min.css +1 -1
  33. package/web/uc-file-uploader-inline.min.js +4 -4
  34. package/web/uc-file-uploader-minimal.min.js +3 -3
  35. package/web/uc-file-uploader-regular.min.css +1 -1
  36. package/web/uc-file-uploader-regular.min.js +4 -4
  37. package/blocks/CameraSource/constants.d.ts +0 -15
  38. package/blocks/CameraSource/constants.d.ts.map +0 -1
  39. package/blocks/CameraSource/constants.js +0 -17
  40. package/blocks/Config/assertions.d.ts +0 -5
  41. package/blocks/Config/assertions.d.ts.map +0 -1
  42. package/blocks/Config/assertions.js +0 -37
  43. package/blocks/Config/side-effects.d.ts +0 -7
  44. package/blocks/Config/side-effects.d.ts.map +0 -1
  45. package/blocks/Config/side-effects.js +0 -32
@@ -1 +1 @@
1
- {"version":3,"file":"UploaderPublicApi.d.ts","sourceRoot":"","sources":["UploaderPublicApi.js"],"names":[],"mappings":"AAaA;IAOE,8DAA8D;IAC9D,iBADY,OAAO,oBAAoB,EAAE,aAAa,EAGrD;IATD;;;OAGG;IACH,aAAK;IAOL,eAAe;IACf,gCAEC;IAED,yCAEC;IAED;;iBAEC;IAED;;;;;;OAMG;IACH,sBAJW,MAAM;;;;sBAEJ,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,wBAJW,MAAM;;;;sBAEJ,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,4BAJW,MAAM;;;;sBAEJ,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAgBrD;IAEF;;;;OAIG;IACH,0BAJW,IAAI;;;;;sBAEF,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAcrD;IAEF,iCAAiC;IACjC,qCADY,MAAM,UAMhB;IAEF,uBAEC;IAED,sBAeE;IAEF,mDAAmD;IACnD,6BADY;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,UAkDrC;IAEF;;;;OAIG;IACH,8EAHW,MAAM,iDA8Cf;IAEF,oEAAoE;IACpE,oKAIE;IAEF,+BAA+B;IAC/B,gDAsCE;IAEF,qBAQE;IAEF;;;;;;;;;OASG;IACH,uTAFQ,IAAI,CAWV;IAEF,2DAA2D;IAC3D,0BADc,OAAO,oBAAoB,EAAE,YAAY,CAGrD;IAEF,8BAA8B;IAC9B,wBADY,OAAO,UAOjB;IAEF;;;OAGG;IACH,0BAOC;CACF"}
1
+ {"version":3,"file":"UploaderPublicApi.d.ts","sourceRoot":"","sources":["UploaderPublicApi.js"],"names":[],"mappings":"AAYA;IAOE,8DAA8D;IAC9D,iBADY,OAAO,oBAAoB,EAAE,aAAa,EAGrD;IATD;;;OAGG;IACH,aAAK;IAOL,eAAe;IACf,gCAEC;IAED,yCAEC;IAED;;iBAEC;IAED;;;;;;OAMG;IACH,sBAJW,MAAM;;;;sBAEJ,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,wBAJW,MAAM;;;;sBAEJ,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAUrD;IAEF;;;;OAIG;IACH,4BAJW,MAAM;;;;sBAEJ,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAgBrD;IAEF;;;;OAIG;IACH,0BAJW,IAAI;;;;;sBAEF,OAAO,UAAU,EAAE,eAAe,CAAC,MAAM,CAAC,CAcrD;IAEF,iCAAiC;IACjC,qCADY,MAAM,UAMhB;IAEF,uBAEC;IAED,sBAeE;IAEF,mDAAmD;IACnD,6BADY;QAAE,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,UA0DrC;IAEF;;;;OAIG;IACH,8EAHW,MAAM,iDA8Cf;IAEF,oEAAoE;IACpE,oKAIE;IAEF,+BAA+B;IAC/B,gDAsCE;IAEF,qBAQE;IAEF;;;;;;;;;OASG;IACH,uTAFQ,IAAI,CAWV;IAEF,2DAA2D;IAC3D,0BADc,OAAO,oBAAoB,EAAE,YAAY,CAGrD;IAEF,8BAA8B;IAC9B,wBADY,OAAO,UAOjB;IAEF;;;OAGG;IACH,0BAOC;CACF"}
@@ -4,12 +4,11 @@ import { ActivityBlock } from './ActivityBlock.js';
4
4
  import { applyStyles, Data } from '@symbiotejs/symbiote';
5
5
  import { EventType } from '../blocks/UploadCtxProvider/EventEmitter.js';
6
6
  import { UploadSource } from '../blocks/utils/UploadSource.js';
7
- import { deserializeCsv, serializeCsv } from '../blocks/utils/comma-separated.js';
7
+ import { serializeCsv } from '../blocks/utils/comma-separated.js';
8
8
  import { IMAGE_ACCEPT_LIST, fileIsImage, mergeFileTypes } from '../utils/fileTypes.js';
9
9
  import { parseCdnUrl } from '../utils/parseCdnUrl.js';
10
10
  import { buildOutputCollectionState } from './buildOutputCollectionState.js';
11
11
  import { stringToArray } from '../utils/stringToArray.js';
12
- import { CameraSourceTypes } from '../blocks/CameraSource/constants.js';
13
12
 
14
13
  export class UploaderPublicApi {
15
14
  /**
@@ -142,6 +141,15 @@ export class UploaderPublicApi {
142
141
  const accept = serializeCsv(
143
142
  mergeFileTypes([this.cfg.accept ?? '', ...(this.cfg.imgOnly ? IMAGE_ACCEPT_LIST : [])]),
144
143
  );
144
+
145
+ if (this.cfg.accept && !!this.cfg.imgOnly) {
146
+ console.warn(
147
+ 'There could be a mistake.\n' +
148
+ 'Both `accept` and `imgOnly` parameters are set.\n' +
149
+ 'The value of `accept` will be concatenated with the internal image mime types list.',
150
+ );
151
+ }
152
+
145
153
  const INPUT_ATTR_NAME = 'uploadcare-file-input';
146
154
  const fileInput = document.createElement('input');
147
155
  fileInput.setAttribute(INPUT_ATTR_NAME, '');
@@ -155,8 +163,7 @@ export class UploaderPublicApi {
155
163
  fileInput.multiple = this.cfg.multiple;
156
164
  if (options.captureCamera) {
157
165
  fileInput.capture = this.cfg.cameraCapture;
158
- const isVideoRecordingEnabled = deserializeCsv(this.cfg.cameraModes).includes(CameraSourceTypes.VIDEO);
159
- fileInput.accept = ['image/*', isVideoRecordingEnabled && 'video/*'].filter(Boolean).join(',');
166
+ fileInput.accept = this.cfg.enableVideoRecording ? ['image/*', 'video/*'].join(',') : 'image/*';
160
167
  } else {
161
168
  fileInput.accept = accept;
162
169
  }
@@ -1,4 +1,4 @@
1
- /** @typedef {'photo' | 'video'} CameraMode */
1
+ /** @typedef {'photo' | 'video'} CameraTabId */
2
2
  /** @typedef {'shot' | 'retake' | 'accept' | 'play' | 'stop' | 'pause' | 'resume'} CameraStatus */
3
3
  export class CameraSource extends UploaderBlock {
4
4
  activityType: "camera";
@@ -32,12 +32,12 @@ export class CameraSource extends UploaderBlock {
32
32
  audioSelectOptions: null;
33
33
  audioSelectHidden: boolean;
34
34
  audioSelectDisabled: boolean;
35
- audioToggleMicrophoneHidden: boolean;
35
+ audioToggleMicorphoneHidden: boolean;
36
36
  tabCameraHidden: boolean;
37
37
  tabVideoHidden: boolean;
38
38
  currentIcon: string;
39
39
  currentTimelineIcon: string;
40
- toggleMicrophoneIcon: string;
40
+ toggleMicorphoneIcon: string;
41
41
  /** @type {Number} */
42
42
  _startTime: number;
43
43
  /** @type {Number} */
@@ -117,10 +117,10 @@ export class CameraSource extends UploaderBlock {
117
117
  _ctx: CanvasRenderingContext2D | null | undefined;
118
118
  /**
119
119
  * @private
120
- * @param {CameraMode} tabId
120
+ * @param {CameraTabId} tabId
121
121
  */
122
122
  private _handleActiveTab;
123
- _activeTab: CameraMode | undefined;
123
+ _activeTab: CameraTabId | undefined;
124
124
  /**
125
125
  * @param {'camera' | 'video'} type
126
126
  * @param {'jpeg' | 'webm'} ext
@@ -136,8 +136,6 @@ export class CameraSource extends UploaderBlock {
136
136
  * @param {File} file
137
137
  */
138
138
  _toSend: (file: File) => void;
139
- /** @private */
140
- private get _cameraModes();
141
139
  /**
142
140
  * @private
143
141
  * @param {'granted' | 'denied' | 'prompt'} state
@@ -152,25 +150,37 @@ export class CameraSource extends UploaderBlock {
152
150
  _getPermission: () => void;
153
151
  _requestDeviceAccess: () => Promise<void>;
154
152
  _getDevices: () => Promise<void>;
155
- _cameraDevices: {
153
+ cameraDevices: {
156
154
  text: string;
157
155
  value: string;
158
156
  }[] | undefined;
159
- _audioDevices: false | {
157
+ audioDevices: false | {
160
158
  text: string;
161
159
  value: string;
162
160
  }[] | undefined;
163
161
  _onActivate: () => Promise<void>;
164
162
  _onDeactivate: () => Promise<void>;
165
- /** @param {CameraMode[]} cameraModes */
166
- _handleCameraModes: (cameraModes: CameraMode[]) => void;
167
163
  _destroy(): void;
168
164
  destroyCallback(): Promise<void>;
169
165
  }
170
166
  export namespace CameraSource {
167
+ let types: Readonly<{
168
+ PHOTO: "photo";
169
+ VIDEO: "video";
170
+ }>;
171
+ let events: Readonly<{
172
+ IDLE: "idle";
173
+ SHOT: "shot";
174
+ PLAY: "play";
175
+ PAUSE: "pause";
176
+ RESUME: "resume";
177
+ STOP: "stop";
178
+ RETAKE: "retake";
179
+ ACCEPT: "accept";
180
+ }>;
171
181
  let template: string;
172
182
  }
173
- export type CameraMode = 'photo' | 'video';
183
+ export type CameraTabId = 'photo' | 'video';
174
184
  export type CameraStatus = 'shot' | 'retake' | 'accept' | 'play' | 'stop' | 'pause' | 'resume';
175
185
  import { UploaderBlock } from '../../abstract/UploaderBlock.js';
176
186
  //# sourceMappingURL=CameraSource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CameraSource.d.ts","sourceRoot":"","sources":["CameraSource.js"],"names":[],"mappings":"AAyCA,8CAA8C;AAE9C,kGAAkG;AAElG;IAEE,uBAA+C;IAE/C,eAAe;IACf,0BAAyB;IAEzB,yBAAyB;IACzB,SADW,QAAQ,EAAE,CACR;IAEb,mCAAmC;IACnC,gBADW,aAAa,GAAG,IAAI,CACT;IAEtB,iCAAiC;IACjC,SADW,WAAW,GAAG,IAAI,CACd;IAEf,4BAA4B;IAC5B,kBADW,MAAM,GAAG,IAAI,CACA;IAExB,4BAA4B;IAC5B,mBADW,MAAM,GAAG,IAAI,CACC;IAKvB;;;;;;;;;;;;;;;;;;;;;;;;QAiCE,qBAAqB;;QAErB,qBAAqB;;;;QAMrB,uBAAuB;kCAAX,KAAK;QAMjB,uBAAuB;iCAAX,KAAK;;;;QAcjB,iDAAiD;;;;;;;;QAejD,4BAA4B;wBAAhB,UAAU;;;;;;;;;;;;;;MAKvB;IAGH,oCAaE;IAEF,yBAkBE;IADA,sCAAiE;IAGnE,wBAKE;IAEF,uBAEE;IAEF,2BAOE;IAEF,0BAEE;IAEF,4BAiCE;IA9BE;;;;;kBAEC;IA8BL,eAAe;IACf,uBAWE;IAEF,2DAA2D;IAC3D,6BAQE;IAEF,+BAOE;IAEF;;;;OAIG;IACH,sBA6BE;IAEF,oBAUE;IAEF,oBAoBE;IAEF,mCAAmC;IACnC,uBADY,YAAY,UAqBtB;IAEF,mCAAmC;IACnC,uBADY,YAAY,UAwCtB;IAEF;;;OAGG;IACH,wBAmBE;IAEF,eAAe;IACf,cAoBC;IAjBC,uCAA+C;IAC/C,kDAAyC;IAkB3C;;;OAGG;IACH,yBAwBE;IADA,mCAAuB;IAGzB;;;;;OAKG;IACH,oBALW,QAAQ,GAAG,OAAO,OAClB,MAAM,GAAG,MAAM,wBAEf,IAAI,UAYb;IAEF,uCAAuC;IACvC,4BADY,SAAS,SAAS,OAmC7B;IAED;;;;OAIG;IACH,gBAFW,IAAI,UAOb;IAEF,eAAe;IACf,2BAEC;IAED;;;OAGG;IACH,6BA+CQ;IAER,6CAQE;IAEF,yBAWE;IAFE,gCAAuB;IAI3B,8BAyCE;IAEF,qCAEE;IAEF,uCAYE;IAEF,2BAA0B;IAE1B,0CASE;IAEF,iCAsCE;IAlCE;;;oBAKK;IAEL;;;oBAOO;IAsBX,iCAME;IAEF,mCAYE;IAEF,wCAAwC;IACxC,kCADY,UAAU,EAAE,UAStB;IAyBF,iBAMC;IAED,iCAIC;CACF;;;;yBAjxBa,OAAO,GAAG,OAAO;2BAEjB,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ;8BAzCnD,iCAAiC"}
1
+ {"version":3,"file":"CameraSource.d.ts","sourceRoot":"","sources":["CameraSource.js"],"names":[],"mappings":"AAsCA,+CAA+C;AAE/C,kGAAkG;AAElG;IAEE,uBAA+C;IAE/C,eAAe;IACf,0BAAyB;IAEzB,yBAAyB;IACzB,SADW,QAAQ,EAAE,CACR;IAEb,mCAAmC;IACnC,gBADW,aAAa,GAAG,IAAI,CACT;IAEtB,iCAAiC;IACjC,SADW,WAAW,GAAG,IAAI,CACd;IAEf,4BAA4B;IAC5B,kBADW,MAAM,GAAG,IAAI,CACA;IAExB,4BAA4B;IAC5B,mBADW,MAAM,GAAG,IAAI,CACC;IAKvB;;;;;;;;;;;;;;;;;;;;;;;;QAiCE,qBAAqB;;QAErB,qBAAqB;;;;QAMrB,uBAAuB;kCAAX,KAAK;QAMjB,uBAAuB;iCAAX,KAAK;;;;QAcjB,iDAAiD;;;;;;;;QAejD,4BAA4B;wBAAhB,UAAU;;;;;;;;;;;;;;MAKvB;IAGH,oCAaE;IAEF,yBAkBE;IADA,sCAAiE;IAGnE,wBAKE;IAEF,uBAEE;IAEF,2BAOE;IAEF,0BAEE;IAEF,4BAiCE;IA9BE;;;;;kBAEC;IA8BL,eAAe;IACf,uBAWE;IAEF,2DAA2D;IAC3D,6BAQE;IAEF,+BAOE;IAEF;;;;OAIG;IACH,sBA6BE;IAEF,oBAUE;IAEF,oBAoBE;IAEF,mCAAmC;IACnC,uBADY,YAAY,UAqBtB;IAEF,mCAAmC;IACnC,uBADY,YAAY,UAuCtB;IAEF;;;OAGG;IACH,wBAmBE;IAEF,eAAe;IACf,cAoBC;IAjBC,uCAA+C;IAC/C,kDAAyC;IAkB3C;;;OAGG;IACH,yBAwBE;IADA,oCAAuB;IAGzB;;;;;OAKG;IACH,oBALW,QAAQ,GAAG,OAAO,OAClB,MAAM,GAAG,MAAM,wBAEf,IAAI,UAYb;IAEF,uCAAuC;IACvC,4BADY,SAAS,SAAS,OAmC7B;IAED;;;;OAIG;IACH,gBAFW,IAAI,UAOb;IAEF;;;OAGG;IACH,6BA8CQ;IAER,6CAQE;IAEF,yBAWE;IAFE,gCAAuB;IAI3B,8BAyCE;IAEF,qCAEE;IAEF,uCAYE;IAEF,2BAA0B;IAE1B,0CASE;IAEF,iCAsCE;IAlCE;;;oBAKK;IAEL;;;oBAOO;IAsBX,iCAIE;IAEF,mCAYE;IAgCF,iBAMC;IAED,iCAIC;CACF;;;;;;;;;;;;;;;;;;0BApwBa,OAAO,GAAG,OAAO;2BAEjB,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ;8BAtCnD,iCAAiC"}
@@ -1,12 +1,9 @@
1
1
  //@ts-nocheck
2
2
  import { ActivityBlock } from '../../abstract/ActivityBlock.js';
3
3
  import { UploaderBlock } from '../../abstract/UploaderBlock.js';
4
- import { stringToArray } from '../../utils/stringToArray.js';
5
4
  import { canUsePermissionsApi } from '../utils/abilities.js';
6
- import { deserializeCsv } from '../utils/comma-separated.js';
7
5
  import { debounce } from '../utils/debounce.js';
8
6
  import { UploadSource } from '../utils/UploadSource.js';
9
- import { CameraSourceEvents, CameraSourceTypes } from './constants.js';
10
7
 
11
8
  const DEFAULT_VIDEO_CONFIG = {
12
9
  width: {
@@ -39,7 +36,7 @@ function formatTime(time) {
39
36
  const DEFAULT_PICTURE_FORMAT = 'image/jpeg';
40
37
  const DEFAULT_VIDEO_FORMAT = 'video/webm';
41
38
 
42
- /** @typedef {'photo' | 'video'} CameraMode */
39
+ /** @typedef {'photo' | 'video'} CameraTabId */
43
40
 
44
41
  /** @typedef {'shot' | 'retake' | 'accept' | 'play' | 'stop' | 'pause' | 'resume'} CameraStatus */
45
42
 
@@ -92,14 +89,14 @@ export class CameraSource extends UploaderBlock {
92
89
  audioSelectOptions: null,
93
90
  audioSelectHidden: true,
94
91
  audioSelectDisabled: true,
95
- audioToggleMicrophoneHidden: true,
92
+ audioToggleMicorphoneHidden: true,
96
93
 
97
94
  tabCameraHidden: true,
98
95
  tabVideoHidden: true,
99
96
 
100
97
  currentIcon: 'camera-full',
101
98
  currentTimelineIcon: 'play',
102
- toggleMicrophoneIcon: 'microphone',
99
+ toggleMicorphoneIcon: 'microphone',
103
100
 
104
101
  /** @type {Number} */
105
102
  _startTime: 0,
@@ -147,17 +144,17 @@ export class CameraSource extends UploaderBlock {
147
144
  /** @param {MouseEvent} e */
148
145
  onClickTab: (e) => {
149
146
  const id = /** @type {HTMLElement} */ (e.currentTarget).getAttribute('data-id');
150
- if (id) this._handleActiveTab(/** @type {CameraMode} */ (id));
147
+ if (id) this._handleActiveTab(/** @type {CameraTabId} */ (id));
151
148
  },
152
149
  };
153
150
  }
154
151
 
155
152
  _chooseActionWithCamera = () => {
156
- if (this._activeTab === CameraSourceTypes.PHOTO) {
153
+ if (this._activeTab === CameraSource.types.PHOTO) {
157
154
  this._shot();
158
155
  }
159
156
 
160
- if (this._activeTab === CameraSourceTypes.VIDEO) {
157
+ if (this._activeTab === CameraSource.types.VIDEO) {
161
158
  if (this._mediaRecorder?.state === 'recording') {
162
159
  this._stopRecording();
163
160
  return;
@@ -215,10 +212,10 @@ export class CameraSource extends UploaderBlock {
215
212
  try {
216
213
  this._chunks = [];
217
214
  this._options = {
218
- ...this.cfg.mediaRecorderOptions,
215
+ ...this.cfg.mediaRecorerOptions,
219
216
  };
220
217
 
221
- const { mimeType } = this.cfg.mediaRecorderOptions || {};
218
+ const { mimeType } = this.cfg.mediaRecorerOptions || {};
222
219
 
223
220
  if (mimeType && MediaRecorder.isTypeSupported(mimeType)) {
224
221
  this._options.mimeType = mimeType;
@@ -239,7 +236,7 @@ export class CameraSource extends UploaderBlock {
239
236
  this._startTimer();
240
237
 
241
238
  this.classList.add('uc-recording');
242
- this._setCameraState(CameraSourceEvents.PLAY);
239
+ this._setCameraState(CameraSource.events.PLAY);
243
240
  }
244
241
  } catch (error) {
245
242
  console.error('Failed to start recording', error);
@@ -253,7 +250,7 @@ export class CameraSource extends UploaderBlock {
253
250
 
254
251
  this._stopTimer();
255
252
 
256
- this._setCameraState(CameraSourceEvents.STOP);
253
+ this._setCameraState(CameraSource.events.STOP);
257
254
  });
258
255
 
259
256
  this._mediaRecorder?.stop();
@@ -275,7 +272,7 @@ export class CameraSource extends UploaderBlock {
275
272
  this._stream?.getAudioTracks().forEach((track) => {
276
273
  track.enabled = !track.enabled;
277
274
 
278
- this.$.toggleMicrophoneIcon = !track.enabled ? 'microphone-mute' : 'microphone';
275
+ this.$.toggleMicorphoneIcon = !track.enabled ? 'microphone-mute' : 'microphone';
279
276
  this.$.audioSelectDisabled = !track.enabled;
280
277
  });
281
278
  };
@@ -317,10 +314,10 @@ export class CameraSource extends UploaderBlock {
317
314
  };
318
315
 
319
316
  _retake = () => {
320
- this._setCameraState(CameraSourceEvents.RETAKE);
317
+ this._setCameraState(CameraSource.events.RETAKE);
321
318
 
322
319
  /** Reset video */
323
- if (this._activeTab === CameraSourceTypes.VIDEO) {
320
+ if (this._activeTab === CameraSource.types.VIDEO) {
324
321
  this.$.video = this._stream;
325
322
  this.ref.video.muted = true;
326
323
  }
@@ -329,9 +326,9 @@ export class CameraSource extends UploaderBlock {
329
326
  };
330
327
 
331
328
  _accept = () => {
332
- this._setCameraState(CameraSourceEvents.ACCEPT);
329
+ this._setCameraState(CameraSource.events.ACCEPT);
333
330
 
334
- if (this._activeTab === CameraSourceTypes.PHOTO) {
331
+ if (this._activeTab === CameraSource.types.PHOTO) {
335
332
  this._canvas?.toBlob((blob) => {
336
333
  const file = this._createFile('camera', 'jpeg', DEFAULT_PICTURE_FORMAT, blob);
337
334
  this._toSend(file);
@@ -352,7 +349,7 @@ export class CameraSource extends UploaderBlock {
352
349
 
353
350
  /** @param {CameraStatus} status */
354
351
  _handlePhoto = (status) => {
355
- if (status === CameraSourceEvents.SHOT) {
352
+ if (status === CameraSource.events.SHOT) {
356
353
  this.set$({
357
354
  tabVideoHidden: true,
358
355
  cameraHidden: true,
@@ -362,20 +359,20 @@ export class CameraSource extends UploaderBlock {
362
359
  });
363
360
  }
364
361
 
365
- if (status === CameraSourceEvents.RETAKE || status === CameraSourceEvents.ACCEPT) {
362
+ if (status === CameraSource.events.RETAKE || status === CameraSource.events.ACCEPT) {
366
363
  this.set$({
367
- tabVideoHidden: !this._cameraModes.includes(CameraSourceTypes.VIDEO),
368
- tabCameraHidden: !this._cameraModes.includes(CameraSourceTypes.PHOTO),
364
+ tabVideoHidden: !this.cfg.enableVideoRecording,
369
365
  cameraHidden: false,
366
+ tabCameraHidden: false,
370
367
  cameraActionsHidden: true,
371
- cameraSelectHidden: this._cameraDevices.length <= 1,
368
+ cameraSelectHidden: this.cameraDevices.length <= 1,
372
369
  });
373
370
  }
374
371
  };
375
372
 
376
373
  /** @param {CameraStatus} status */
377
374
  _handleVideo = (status) => {
378
- if (status === CameraSourceEvents.PLAY) {
375
+ if (status === CameraSource.events.PLAY) {
379
376
  this.set$({
380
377
  timerHidden: false,
381
378
  tabCameraHidden: true,
@@ -389,28 +386,27 @@ export class CameraSource extends UploaderBlock {
389
386
  });
390
387
  }
391
388
 
392
- if (status === CameraSourceEvents.STOP) {
389
+ if (status === CameraSource.events.STOP) {
393
390
  this.set$({
394
391
  timerHidden: false,
395
392
  cameraHidden: true,
396
- audioToggleMicrophoneHidden: true,
393
+ audioToggleMicorphoneHidden: true,
397
394
  cameraActionsHidden: false,
398
395
  });
399
396
  }
400
397
 
401
- if (status === CameraSourceEvents.RETAKE || status === CameraSourceEvents.ACCEPT) {
398
+ if (status === CameraSource.events.RETAKE || status === CameraSource.events.ACCEPT) {
402
399
  this.set$({
403
400
  timerHidden: true,
404
- tabVideoHidden: !this._cameraModes.includes(CameraSourceTypes.VIDEO),
405
- tabCameraHidden: !this._cameraModes.includes(CameraSourceTypes.PHOTO),
401
+ tabCameraHidden: false,
406
402
  cameraHidden: false,
407
403
  cameraActionsHidden: true,
408
- audioToggleMicrophoneHidden: !this.cfg.enableAudioRecording,
404
+ audioToggleMicorphoneHidden: !this.cfg.enableAudioRecording,
409
405
  currentIcon: 'video-camera-full',
410
406
  mutableClassButton: 'uc-shot-btn uc-camera-action',
411
407
 
412
- audioSelectHidden: !this.cfg.enableAudioRecording || this._audioDevices.length <= 1,
413
- cameraSelectHidden: this._cameraDevices.length <= 1,
408
+ audioSelectHidden: !this.cfg.enableAudioRecording || this.audioDevices.length <= 1,
409
+ cameraSelectHidden: this.cameraDevices.length <= 1,
414
410
  });
415
411
  }
416
412
  };
@@ -421,14 +417,14 @@ export class CameraSource extends UploaderBlock {
421
417
  */
422
418
  _setCameraState = (status) => {
423
419
  if (
424
- this._activeTab === CameraSourceTypes.PHOTO &&
420
+ this._activeTab === CameraSource.types.PHOTO &&
425
421
  (status === 'shot' || status === 'retake' || status === 'accept')
426
422
  ) {
427
423
  this._handlePhoto(status);
428
424
  }
429
425
 
430
426
  if (
431
- this._activeTab === CameraSourceTypes.VIDEO &&
427
+ this._activeTab === CameraSource.types.VIDEO &&
432
428
  (status === 'play' ||
433
429
  status === 'stop' ||
434
430
  status === 'retake' ||
@@ -465,28 +461,28 @@ export class CameraSource extends UploaderBlock {
465
461
 
466
462
  /**
467
463
  * @private
468
- * @param {CameraMode} tabId
464
+ * @param {CameraTabId} tabId
469
465
  */
470
466
  _handleActiveTab = (tabId) => {
471
467
  this.ref.switcher.querySelectorAll('button').forEach((/** @type {HTMLElement} */ btn) => {
472
468
  btn.classList.toggle('uc-active', btn.getAttribute('data-id') === tabId);
473
469
  });
474
470
 
475
- if (tabId === CameraSourceTypes.PHOTO) {
471
+ if (tabId === CameraSource.types.PHOTO) {
476
472
  this.set$({
477
473
  currentIcon: 'camera-full',
478
474
  audioSelectHidden: true,
479
- audioToggleMicrophoneHidden: true,
475
+ audioToggleMicorphoneHidden: true,
480
476
  });
481
477
  }
482
478
 
483
- if (tabId === CameraSourceTypes.VIDEO) {
479
+ if (tabId === CameraSource.types.VIDEO) {
484
480
  this.set$({
485
481
  currentTimelineIcon: 'play',
486
482
  currentIcon: 'video-camera-full',
487
483
 
488
- audioSelectHidden: !this.cfg.enableAudioRecording || this._audioDevices.length <= 1,
489
- audioToggleMicrophoneHidden: !this.cfg.enableAudioRecording,
484
+ audioSelectHidden: !this.cfg.enableAudioRecording || this.audioDevices.length <= 1,
485
+ audioToggleMicorphoneHidden: !this.cfg.enableAudioRecording,
490
486
  });
491
487
  }
492
488
 
@@ -560,11 +556,6 @@ export class CameraSource extends UploaderBlock {
560
556
  });
561
557
  };
562
558
 
563
- /** @private */
564
- get _cameraModes() {
565
- return stringToArray(this.cfg.cameraModes);
566
- }
567
-
568
559
  /**
569
560
  * @private
570
561
  * @param {'granted' | 'denied' | 'prompt'} state
@@ -572,20 +563,19 @@ export class CameraSource extends UploaderBlock {
572
563
  _setPermissionsState = debounce((state) => {
573
564
  this.classList.toggle('uc-initialized', state === 'granted');
574
565
 
575
- const visibleAudio = this._activeTab === CameraSourceTypes.VIDEO && this.cfg.enableAudioRecording;
576
- const currentIcon = this._activeTab === CameraSourceTypes.PHOTO ? 'camera-full' : 'video-camera-full';
566
+ const visibleAudio = this._activeTab === CameraSource.types.VIDEO && this.cfg.enableAudioRecording;
567
+ const currentIcon = this._activeTab === CameraSource.types.PHOTO ? 'camera-full' : 'video-camera-full';
577
568
 
578
569
  if (state === 'granted') {
579
570
  this.set$({
580
571
  videoHidden: false,
581
572
  cameraHidden: false,
582
- tabCameraHidden: !this._cameraModes.includes(CameraSourceTypes.PHOTO),
583
- tabVideoHidden: !this._cameraModes.includes(CameraSourceTypes.VIDEO),
573
+ tabCameraHidden: false,
584
574
  messageHidden: true,
585
575
  timerHidden: true,
586
576
 
587
577
  currentIcon,
588
- audioToggleMicrophoneHidden: !visibleAudio,
578
+ audioToggleMicorphoneHidden: !visibleAudio,
589
579
  audioSelectHidden: !visibleAudio,
590
580
  });
591
581
  } else if (state === 'prompt') {
@@ -606,8 +596,8 @@ export class CameraSource extends UploaderBlock {
606
596
  videoHidden: true,
607
597
  messageHidden: false,
608
598
 
609
- tabCameraHidden: !this._cameraModes.includes(CameraSourceTypes.PHOTO),
610
- tabVideoHidden: !this._cameraModes.includes(CameraSourceTypes.VIDEO),
599
+ tabCameraHidden: false,
600
+ tabVideoHidden: !this.cfg.enableVideoRecording,
611
601
 
612
602
  cameraActionsHidden: true,
613
603
 
@@ -719,14 +709,14 @@ export class CameraSource extends UploaderBlock {
719
709
  try {
720
710
  const devices = await navigator.mediaDevices.enumerateDevices();
721
711
 
722
- this._cameraDevices = devices
712
+ this.cameraDevices = devices
723
713
  .filter((device) => device.kind === 'videoinput')
724
714
  .map((device, index) => ({
725
715
  text: device.label.trim() || `${this.l10n('caption-camera')} ${index + 1}`,
726
716
  value: device.deviceId,
727
717
  }));
728
718
 
729
- this._audioDevices =
719
+ this.audioDevices =
730
720
  this.cfg.enableAudioRecording &&
731
721
  devices
732
722
  .filter((device) => device.kind === 'audioinput')
@@ -735,21 +725,21 @@ export class CameraSource extends UploaderBlock {
735
725
  value: device.deviceId,
736
726
  }));
737
727
 
738
- if (this._cameraDevices.length > 1) {
728
+ if (this.cameraDevices.length > 1) {
739
729
  this.set$({
740
- cameraSelectOptions: this._cameraDevices,
730
+ cameraSelectOptions: this.cameraDevices,
741
731
  cameraSelectHidden: false,
742
732
  });
743
733
  }
744
- this._selectedCameraId = this._cameraDevices[0]?.value;
734
+ this._selectedCameraId = this.cameraDevices[0]?.value;
745
735
 
746
- if (this._audioDevices.length > 1) {
736
+ if (this.audioDevices.length > 1) {
747
737
  this.set$({
748
- audioSelectOptions: this._audioDevices,
738
+ audioSelectOptions: this.audioDevices,
749
739
  audioSelectHidden: false,
750
740
  });
751
741
  }
752
- this._selectedAudioId = this._audioDevices[0]?.value;
742
+ this._selectedAudioId = this.audioDevices[0]?.value;
753
743
  } catch (error) {
754
744
  console.log('Failed to get devices', error);
755
745
  }
@@ -759,8 +749,6 @@ export class CameraSource extends UploaderBlock {
759
749
  await this._permissionAccess();
760
750
  await this._requestDeviceAccess();
761
751
  await this._capture();
762
-
763
- this._handleCameraModes(this._cameraModes);
764
752
  };
765
753
 
766
754
  _onDeactivate = async () => {
@@ -777,17 +765,6 @@ export class CameraSource extends UploaderBlock {
777
765
  this._stopCapture();
778
766
  };
779
767
 
780
- /** @param {CameraMode[]} cameraModes */
781
- _handleCameraModes = (cameraModes) => {
782
- this.$.tabVideoHidden = !cameraModes.includes(CameraSourceTypes.VIDEO);
783
- this.$.tabCameraHidden = !cameraModes.includes(CameraSourceTypes.PHOTO);
784
-
785
- const defaultTab = cameraModes[0];
786
- if (!this._activeTab || !cameraModes.includes(this._activeTab)) {
787
- this._handleActiveTab(defaultTab);
788
- }
789
- };
790
-
791
768
  initCallback() {
792
769
  super.initCallback();
793
770
  this.registerActivity(this.activityType, {
@@ -800,14 +777,21 @@ export class CameraSource extends UploaderBlock {
800
777
  });
801
778
 
802
779
  this.subConfigValue('enableAudioRecording', (val) => {
803
- this.$.audioToggleMicrophoneHidden = !val;
780
+ this.$.audioToggleMicorphoneHidden = !val;
804
781
  this.$.audioSelectDisabled = !val;
805
782
  });
806
783
 
807
- this.subConfigValue('cameraModes', (val) => {
808
- if (!this.isActivityActive) return;
809
- const cameraModes = deserializeCsv(val);
810
- this._handleCameraModes(cameraModes);
784
+ this.subConfigValue('enableVideoRecording', (val) => {
785
+ this.$.tabVideoHidden = !val;
786
+ });
787
+
788
+ this.subConfigValue('defaultCameraMode', (val) => {
789
+ if (this.cfg.enableVideoRecording) {
790
+ this._handleActiveTab(val);
791
+ return;
792
+ }
793
+
794
+ this._handleActiveTab('photo');
811
795
  });
812
796
  }
813
797
 
@@ -826,6 +810,24 @@ export class CameraSource extends UploaderBlock {
826
810
  }
827
811
  }
828
812
 
813
+ CameraSource.types = Object.freeze({
814
+ PHOTO: 'photo',
815
+ VIDEO: 'video',
816
+ });
817
+
818
+ CameraSource.events = Object.freeze({
819
+ IDLE: 'idle',
820
+ SHOT: 'shot',
821
+
822
+ PLAY: 'play',
823
+ PAUSE: 'pause',
824
+ RESUME: 'resume',
825
+ STOP: 'stop',
826
+
827
+ RETAKE: 'retake',
828
+ ACCEPT: 'accept',
829
+ });
830
+
829
831
  CameraSource.template = /* HTML */ `
830
832
  <uc-activity-header>
831
833
  <button type="button" class="uc-mini-btn" set="onclick: *historyBack" l10n="@title:back">
@@ -880,7 +882,7 @@ CameraSource.template = /* HTML */ `
880
882
  <button
881
883
  data-id="video"
882
884
  type="button"
883
- class="uc-switch uc-mini-btn"
885
+ class="uc-switch uc-mini-btn"
884
886
  set="onclick: onClickTab; @hidden: tabVideoHidden"
885
887
  >
886
888
  <uc-icon name="video-camera"></uc-icon>
@@ -907,8 +909,8 @@ CameraSource.template = /* HTML */ `
907
909
  </button>
908
910
 
909
911
  <div class="uc-select">
910
- <button class="uc-mini-btn uc-btn-microphone" set="onclick: onToggleAudio; @hidden: audioToggleMicrophoneHidden;">
911
- <uc-icon set="@name:toggleMicrophoneIcon"></uc-icon>
912
+ <button class="uc-mini-btn uc-btn-microphone" set="onclick: onToggleAudio; @hidden: audioToggleMicorphoneHidden;">
913
+ <uc-icon set="@name:toggleMicorphoneIcon"></uc-icon>
912
914
  </button>
913
915
 
914
916
  <uc-select
@@ -109,7 +109,6 @@ uc-camera-source .uc-controls {
109
109
 
110
110
  uc-camera-source .uc-switcher {
111
111
  display: flex;
112
- gap: var(--uc-padding);
113
112
  }
114
113
  uc-camera-source .uc-switch.uc-active {
115
114
  background-color: var(--uc-secondary);
@@ -138,6 +138,13 @@ export class CropFrame extends Block {
138
138
  } | undefined;
139
139
  /** @private */
140
140
  private _updateCursor;
141
+ /**
142
+ * @private
143
+ * @param {String} href
144
+ */
145
+ private _createMask;
146
+ _frameImage: SVGElement | undefined;
147
+ _updateMask(): void;
141
148
  /** @private */
142
149
  private _render;
143
150
  /** @param {boolean} visible */
@@ -1 +1 @@
1
- {"version":3,"file":"CropFrame.d.ts","sourceRoot":"","sources":["CropFrame.js"],"names":[],"mappings":"AA2BA;IAII;;MAGC;IAED,eAAe;IACf,yBAAyD;IAEzD,eAAe;IACf,2BAA6D;IAE7D,eAAe;IACf,8BAAmE;IAGrE;;;OAGG;IACH,+BAaC;IAED,eAAe;IACf,wBAyCC;IAFC,sCAAyB;IACzB,2CAAuC;IAGzC;;;OAGG;IACH,wBAUC;IAED,eAAe;IACf,wBASC;IAED,eAAe;IACf,qBAgEC;IAED;;;OAGG;IACH,0BAHW,OAAO,YAAY,EAAE,WAAW,aAChC,OAAO,YAAY,EAAE,SAAS,QA4BxC;IAED,eAAe;IACf,sBAiBC;IAED,eAAe;IACf,sBA4CC;IAED,eAAe;IACf,qBAeC;IAFC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAA+B;IAC/B,qCAA+B;IAGjC;;;;OAIG;IACH,2BAiBC;IAJC;;;;;kBAA2B;IAC3B,sCAA6B;IAC7B,6CAA6C;IAC7C,2DAAoC;IAGtC;;;OAGG;IACH,0BAUC;IAED;;;OAGG;IACH,4BAmBC;IAED;;;;OAIG;IACH,qBAsBC;IAED;;;OAGG;IACH,+BAqBC;IAFC;;;;;kBAA6B;IAI/B,eAAe;IACf,sBAGC;IAED,eAAe;IACf,gBAGC;IAED,+BAA+B;IAC/B,sBADY,OAAO,QAclB;IAmBG,mCAAsF;CA6B3F;;;;sBAngBqB,4BAA4B"}
1
+ {"version":3,"file":"CropFrame.d.ts","sourceRoot":"","sources":["CropFrame.js"],"names":[],"mappings":"AA2BA;IAII;;MAGC;IAED,eAAe;IACf,yBAAyD;IAEzD,eAAe;IACf,2BAA6D;IAE7D,eAAe;IACf,8BAAmE;IAGrE;;;OAGG;IACH,+BAaC;IAED,eAAe;IACf,wBAyCC;IAFC,sCAAyB;IACzB,2CAAuC;IAGzC;;;OAGG;IACH,wBAUC;IAED,eAAe;IACf,wBASC;IAED,eAAe;IACf,qBAgEC;IAED;;;OAGG;IACH,0BAHW,OAAO,YAAY,EAAE,WAAW,aAChC,OAAO,YAAY,EAAE,SAAS,QA4BxC;IAED,eAAe;IACf,sBAiBC;IAED,eAAe;IACf,sBA4CC;IAED,eAAe;IACf,qBAeC;IAFC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAA+B;IAC/B,qCAA+B;IAGjC;;;;OAIG;IACH,2BAiBC;IAJC;;;;;kBAA2B;IAC3B,sCAA6B;IAC7B,6CAA6C;IAC7C,2DAAoC;IAGtC;;;OAGG;IACH,0BAUC;IAED;;;OAGG;IACH,4BAmBC;IAED;;;;OAIG;IACH,qBAsBC;IAED;;;OAGG;IACH,+BAqBC;IAFC;;;;;kBAA6B;IAI/B,eAAe;IACf,sBAGC;IAED;;;OAGG;IACH,oBAoBC;IADC,oCAA4B;IAG9B,oBAeC;IAED,eAAe;IACf,gBAIC;IAED,+BAA+B;IAC/B,sBADY,OAAO,QAclB;IAmBG,mCAAsF;CAmC3F;;;;sBArjBqB,4BAA4B"}
@@ -446,10 +446,54 @@ export class CropFrame extends Block {
446
446
  this.ref['svg-el'].style.cursor = hoverThumb ? thumbCursor(hoverThumb.direction) : 'initial';
447
447
  }
448
448
 
449
+ /**
450
+ * @private
451
+ * @param {String} href
452
+ */
453
+ _createMask(href) {
454
+ if (this._frameImage) {
455
+ this._frameImage.setAttribute('href', href);
456
+ return;
457
+ }
458
+
459
+ let svg = this.ref['svg-el'];
460
+ let fr = document.createDocumentFragment();
461
+
462
+ let imageNode = createSvgNode('image', {
463
+ href,
464
+ });
465
+
466
+ imageNode.setAttribute('class', 'uc-cloud-mask');
467
+
468
+ fr.appendChild(imageNode);
469
+
470
+ svg.appendChild(fr);
471
+
472
+ this._frameImage = imageNode;
473
+ }
474
+
475
+ _updateMask() {
476
+ let cropBox = this.$['*cropBox'];
477
+
478
+ if (!cropBox || !this._frameImage) {
479
+ return;
480
+ }
481
+
482
+ let { x, y, width, height } = cropBox;
483
+
484
+ setSvgNodeAttrs(this._frameImage, {
485
+ x,
486
+ y,
487
+ height,
488
+ width,
489
+ });
490
+ }
491
+
449
492
  /** @private */
450
493
  _render() {
451
494
  this._updateBackdrop();
452
495
  this._updateFrame();
496
+ this._updateMask();
453
497
  }
454
498
 
455
499
  /** @param {boolean} visible */
@@ -491,6 +535,12 @@ export class CropFrame extends Block {
491
535
  });
492
536
  });
493
537
 
538
+ this.subConfigValue('cloudImageEditorMaskHref', (maskHref) => {
539
+ if (maskHref) {
540
+ this._createMask(maskHref);
541
+ }
542
+ });
543
+
494
544
  this.sub('dragging', (dragging) => {
495
545
  if (!this._frameGuides) return;
496
546
  this._frameGuides.setAttribute(