videomail-client 16.4.1 → 16.6.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.
package/dist/esm/index.js CHANGED
@@ -69,12 +69,12 @@ __webpack_require__.m = __webpack_modules__;
69
69
  __webpack_require__.nc = void 0;
70
70
  })();
71
71
  __webpack_require__.add({
72
- pJ (module, __webpack_exports__, __webpack_require__) {
73
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1 = __webpack_require__("K7");
74
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1_default = /*#__PURE__*/ __webpack_require__.n(_node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1);
75
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0 = __webpack_require__("L");
76
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0_default = /*#__PURE__*/ __webpack_require__.n(_node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0);
77
- var ___CSS_LOADER_EXPORT___ = _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0_default()(_node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1_default());
72
+ eq (module, __webpack_exports__, __webpack_require__) {
73
+ var _node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1 = __webpack_require__("er");
74
+ var _node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1_default = /*#__PURE__*/ __webpack_require__.n(_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1);
75
+ var _node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0 = __webpack_require__("zm");
76
+ var _node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0_default = /*#__PURE__*/ __webpack_require__.n(_node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0);
77
+ var ___CSS_LOADER_EXPORT___ = _node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0_default()(_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1_default());
78
78
  ___CSS_LOADER_EXPORT___.push([
79
79
  module.id,
80
80
  `@keyframes blink {
@@ -3378,7 +3378,7 @@ __webpack_require__.add({
3378
3378
  }
3379
3379
  module.exports = whichTypedArray;
3380
3380
  },
3381
- L (module) {
3381
+ zm (module) {
3382
3382
  module.exports = function(cssWithMappingToString) {
3383
3383
  var list = [];
3384
3384
  list.toString = function() {
@@ -3431,12 +3431,12 @@ __webpack_require__.add({
3431
3431
  return list;
3432
3432
  };
3433
3433
  },
3434
- K7 (module) {
3434
+ er (module) {
3435
3435
  module.exports = function(i) {
3436
3436
  return i[1];
3437
3437
  };
3438
3438
  },
3439
- qB (module) {
3439
+ RR (module) {
3440
3440
  var stylesInDOM = [];
3441
3441
  function getIndexByIdentifier(identifier) {
3442
3442
  var result = -1;
@@ -3514,7 +3514,7 @@ __webpack_require__.add({
3514
3514
  };
3515
3515
  };
3516
3516
  },
3517
- fR (module) {
3517
+ uZ (module) {
3518
3518
  var memo = {};
3519
3519
  function getTarget(target) {
3520
3520
  if (void 0 === memo[target]) {
@@ -3535,7 +3535,7 @@ __webpack_require__.add({
3535
3535
  }
3536
3536
  module.exports = insertBySelector;
3537
3537
  },
3538
- z7 (module) {
3538
+ mK (module) {
3539
3539
  function insertStyleElement(options) {
3540
3540
  var element = document.createElement("style");
3541
3541
  options.setAttributes(element, options.attributes);
@@ -3544,14 +3544,14 @@ __webpack_require__.add({
3544
3544
  }
3545
3545
  module.exports = insertStyleElement;
3546
3546
  },
3547
- g2 (module, __unused_rspack_exports, __webpack_require__) {
3547
+ kU (module, __unused_rspack_exports, __webpack_require__) {
3548
3548
  function setAttributesWithoutAttributes(styleElement) {
3549
3549
  var nonce = __webpack_require__.nc;
3550
3550
  if (nonce) styleElement.setAttribute("nonce", nonce);
3551
3551
  }
3552
3552
  module.exports = setAttributesWithoutAttributes;
3553
3553
  },
3554
- Vq (module) {
3554
+ Bd (module) {
3555
3555
  function apply(styleElement, options, obj) {
3556
3556
  var css = "";
3557
3557
  if (obj.supports) css += "@supports (".concat(obj.supports, ") {");
@@ -3587,7 +3587,7 @@ __webpack_require__.add({
3587
3587
  }
3588
3588
  module.exports = domAPI;
3589
3589
  },
3590
- AD (module) {
3590
+ snK (module) {
3591
3591
  function styleTagTransform(css, styleElement) {
3592
3592
  if (styleElement.styleSheet) styleElement.styleSheet.cssText = css;
3593
3593
  else {
@@ -3620,7 +3620,7 @@ const constants = {
3620
3620
  }
3621
3621
  };
3622
3622
  var package_namespaceObject = {
3623
- rE: "16.4.1"
3623
+ rE: "16.6.0"
3624
3624
  };
3625
3625
  function isAudioEnabled(options) {
3626
3626
  return Boolean(options.audio.enabled);
@@ -3885,12 +3885,12 @@ function createError(errorParams) {
3885
3885
  const errName = err?.name ?? err?.constructor.name;
3886
3886
  switch(errName){
3887
3887
  case error_VideomailError.SECURITY_ERROR:
3888
- message = "The operation was insecure";
3889
- explanation = "Probably you have disallowed Cookies for this page?";
3888
+ message = "Your browser blocked this action";
3889
+ explanation = "Check this page's camera permissions and security settings.";
3890
3890
  classList.push(error_VideomailError.BROWSER_PROBLEM);
3891
3891
  break;
3892
3892
  case error_VideomailError.OVERCONSTRAINED:
3893
- message = "Invalid webcam constraints";
3893
+ message = "Your webcam cannot use these settings";
3894
3894
  if (err && "constraint" in err) {
3895
3895
  const overconstrainedError = err;
3896
3896
  const constraint = overconstrainedError.constraint;
@@ -3901,64 +3901,64 @@ function createError(errorParams) {
3901
3901
  break;
3902
3902
  case "MediaDeviceFailedDueToShutdown":
3903
3903
  message = "Webcam is shutting down";
3904
- explanation = "This happens your webcam is already switching off and not giving you permission to use it.";
3904
+ explanation = "Wait for your webcam to finish switching off, then try again.";
3905
3905
  break;
3906
3906
  case "SourceUnavailableError":
3907
- message = "Source of your webcam cannot be accessed";
3908
- explanation = "Probably it is locked from another process or has a hardware error.";
3907
+ message = "Cannot access your webcam";
3908
+ explanation = "Another app may be using it, or there may be a hardware problem.";
3909
3909
  break;
3910
3910
  case "NO_DEVICES_FOUND":
3911
3911
  if (audioEnabled) {
3912
- message = "No webcam nor microphone found";
3913
- explanation = "Your browser cannot find a webcam with microphone attached to your machine.";
3912
+ message = "No webcam or microphone found";
3913
+ explanation = "Check that your webcam and microphone are connected.";
3914
3914
  } else {
3915
3915
  message = "No webcam found";
3916
- explanation = "Your browser cannot find a webcam attached to your machine.";
3916
+ explanation = "Check that your webcam is connected.";
3917
3917
  }
3918
3918
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3919
3919
  break;
3920
3920
  case "PermissionDismissedError":
3921
- message = "Ooops, you didn't give me any permissions?";
3922
- explanation = "Looks like you skipped the webcam permission dialogue.<br/>Please grant access next time the dialogue appears.";
3921
+ message = "Camera permission is needed";
3922
+ explanation = "The camera permission prompt was closed.<br/>Please allow access when it appears again.";
3923
3923
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3924
3924
  break;
3925
3925
  case error_VideomailError.NOT_ALLOWED_ERROR:
3926
3926
  case error_VideomailError.PERMISSION_DENIED:
3927
3927
  case "PermissionDeniedError":
3928
3928
  message = "Permission denied";
3929
- explanation = "Cannot access your webcam. This can have two reasons:<br/>a) you blocked access to webcam; or<br/>b) your webcam is already in use.";
3929
+ explanation = "We cannot access your webcam. Check these possibilities:<ul><li>Camera access is blocked in your browser settings.</li><li>Another app is using your webcam.</li></ul>";
3930
3930
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3931
3931
  break;
3932
3932
  case "HARDWARE_UNAVAILABLE":
3933
3933
  case "AbortError":
3934
3934
  message = "Webcam is unavailable";
3935
- explanation = "Maybe it is already busy in another window?";
3935
+ explanation = "Another window may be using it. Close it and try again.";
3936
3936
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3937
3937
  break;
3938
3938
  case "NO_VIDEO_FEED":
3939
- message = "No video feed found!";
3940
- explanation = "Your webcam is already used in another browser.";
3939
+ message = "No video feed found";
3940
+ explanation = "Another browser may be using your webcam.";
3941
3941
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3942
3942
  break;
3943
3943
  case error_VideomailError.STARTING_FAILED:
3944
- message = "Starting video failed";
3945
- explanation = "Most likely this happens when the webcam is already active in another browser";
3944
+ message = "Could not start recording";
3945
+ explanation = "Another browser may be using your webcam.";
3946
3946
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3947
3947
  break;
3948
3948
  case "DevicesNotFoundError":
3949
- message = "No available webcam could be found";
3950
- explanation = "Looks like you do not have any webcam attached to your machine; or the one you plugged in is already used.";
3949
+ message = "No available webcam found";
3950
+ explanation = "Check that your webcam is connected and not being used by another app.";
3951
3951
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3952
3952
  break;
3953
3953
  case error_VideomailError.NOT_READABLE_ERROR:
3954
3954
  case error_VideomailError.TRACK_START_ERROR:
3955
- message = "No access to webcam";
3956
- explanation = "Perhaps you are already using it in another browser?";
3955
+ message = "Cannot access your webcam";
3956
+ explanation = "Another browser may be using it. Close it and try again.";
3957
3957
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3958
3958
  break;
3959
3959
  case error_VideomailError.INVALID_STATE_ERROR:
3960
- message = "Invalid state";
3961
- explanation = "Video recording stream from your webcam already has finished";
3960
+ message = "Your camera stream has ended";
3961
+ explanation = "The webcam stream is no longer active.";
3962
3962
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
3963
3963
  break;
3964
3964
  case error_VideomailError.DOM_EXCEPTION:
@@ -4286,6 +4286,17 @@ class Form extends util_Despot {
4286
4286
  enable(buttonsToo) {
4287
4287
  this.setDisabled(false, buttonsToo);
4288
4288
  }
4289
+ disableForSubmission() {
4290
+ for (const formControl of this.formElement.elements){
4291
+ this.submissionDisabledStates.set(formControl, formControl.hasAttribute("disabled"));
4292
+ formControl.setAttribute("disabled", "disabled");
4293
+ }
4294
+ }
4295
+ restoreAfterFailedSubmission() {
4296
+ for (const [formControl, wasDisabled] of this.submissionDisabledStates)if (wasDisabled) formControl.setAttribute("disabled", "disabled");
4297
+ else formControl.removeAttribute("disabled");
4298
+ this.submissionDisabledStates.clear();
4299
+ }
4289
4300
  build() {
4290
4301
  this.options.logger.debug("Form: build()");
4291
4302
  this.keyInput = this.formElement.querySelector(`input[name="${this.options.selectors.keyInputName}"]`);
@@ -4446,7 +4457,7 @@ class Form extends util_Despot {
4446
4457
  html_showElement(this.formElement);
4447
4458
  }
4448
4459
  constructor(container, formElement, options){
4449
- super("Form", options), form_define_property(this, "container", void 0), form_define_property(this, "formElement", void 0), form_define_property(this, "keyInput", void 0), form_define_property(this, "submitButton", void 0), form_define_property(this, "submitButtonFormAttribute", null), form_define_property(this, "generatedFormId", void 0), form_define_property(this, "isSubmitting", false), form_define_property(this, "FORM_FIELDS", {}), form_define_property(this, "validate", (event)=>{
4460
+ super("Form", options), form_define_property(this, "container", void 0), form_define_property(this, "formElement", void 0), form_define_property(this, "keyInput", void 0), form_define_property(this, "submitButton", void 0), form_define_property(this, "submitButtonFormAttribute", null), form_define_property(this, "generatedFormId", void 0), form_define_property(this, "isSubmitting", false), form_define_property(this, "submissionDisabledStates", new Map()), form_define_property(this, "FORM_FIELDS", {}), form_define_property(this, "validate", (event)=>{
4450
4461
  this.container.validate(event);
4451
4462
  }), form_define_property(this, "handleSubmit", (event)=>{
4452
4463
  if (!event.defaultPrevented) this.doTheSubmit(event);
@@ -4855,18 +4866,18 @@ function mergeWithDefaultOptions(options = {}) {
4855
4866
  return newOptions;
4856
4867
  }
4857
4868
  const options_mergeWithDefaultOptions = mergeWithDefaultOptions;
4858
- const main_0 = __webpack_require__("pJ");
4859
- const styleTagTransform = __webpack_require__("AD");
4869
+ const main_0 = __webpack_require__("eq");
4870
+ const styleTagTransform = __webpack_require__("snK");
4860
4871
  var styleTagTransform_default = /*#__PURE__*/ __webpack_require__.n(styleTagTransform);
4861
- const setAttributesWithoutAttributes = __webpack_require__("g2");
4872
+ const setAttributesWithoutAttributes = __webpack_require__("kU");
4862
4873
  var setAttributesWithoutAttributes_default = /*#__PURE__*/ __webpack_require__.n(setAttributesWithoutAttributes);
4863
- const insertBySelector = __webpack_require__("fR");
4874
+ const insertBySelector = __webpack_require__("uZ");
4864
4875
  var insertBySelector_default = /*#__PURE__*/ __webpack_require__.n(insertBySelector);
4865
- const styleDomAPI = __webpack_require__("Vq");
4876
+ const styleDomAPI = __webpack_require__("Bd");
4866
4877
  var styleDomAPI_default = /*#__PURE__*/ __webpack_require__.n(styleDomAPI);
4867
- const insertStyleElement = __webpack_require__("z7");
4878
+ const insertStyleElement = __webpack_require__("mK");
4868
4879
  var insertStyleElement_default = /*#__PURE__*/ __webpack_require__.n(insertStyleElement);
4869
- const injectStylesIntoStyleTag = __webpack_require__("qB");
4880
+ const injectStylesIntoStyleTag = __webpack_require__("RR");
4870
4881
  var injectStylesIntoStyleTag_default = /*#__PURE__*/ __webpack_require__.n(injectStylesIntoStyleTag);
4871
4882
  var main_options = {};
4872
4883
  main_options.styleTagTransform = styleTagTransform_default();
@@ -5085,8 +5096,13 @@ class Buttons extends util_Despot {
5085
5096
  this.hide();
5086
5097
  }
5087
5098
  onUserMediaReady(params) {
5088
- this.onFormReady();
5099
+ this.onFormReady(params);
5089
5100
  html_showElement(this.buttonsElement);
5101
+ if (params.recovering && params.paused) {
5102
+ html_hideElement(this.recordButton);
5103
+ html_disableElement(this.recordButton);
5104
+ return;
5105
+ }
5090
5106
  html_showElement(this.audioOnRadioPair);
5091
5107
  html_showElement(this.audioOffRadioPair);
5092
5108
  if (html_isShown(this.recordButton) && !params.recordWhenReady) html_enableElement(this.recordButton);
@@ -5789,8 +5805,8 @@ class RecorderInsides extends util_Despot {
5789
5805
  this.on("PAUSED", ()=>{
5790
5806
  this.pauseRecording();
5791
5807
  });
5792
- this.on("ERROR", ()=>{
5793
- this.onResetting();
5808
+ this.on("ERROR", ({ recoverable })=>{
5809
+ if (!recoverable) this.onResetting();
5794
5810
  });
5795
5811
  this.on("RESETTING", ()=>{
5796
5812
  this.onResetting();
@@ -5973,12 +5989,12 @@ class Notifier extends util_Despot {
5973
5989
  this.entertainTimeoutId = void 0;
5974
5990
  this.entertaining = false;
5975
5991
  }
5976
- error(err) {
5992
+ error(err, blocking = true) {
5977
5993
  const message = err.message;
5978
5994
  const explanation = err.explanation;
5979
5995
  if (!message) this.options.logger.debug(`Weird empty error message generated for error ${string_pretty(err)}`);
5980
5996
  this.notify(message, explanation, {
5981
- blocking: true,
5997
+ blocking,
5982
5998
  problem: true,
5983
5999
  classList: err.getClassList(),
5984
6000
  removeDimensions: util_getBrowser(this.options).isMobile()
@@ -7332,6 +7348,9 @@ class RecorderCapture extends media {
7332
7348
  if (this.streamBackpressured) this.resumeAfterDrain = true;
7333
7349
  else loop.start();
7334
7350
  }
7351
+ resumeMediaForCountdown() {
7352
+ this.userMedia?.resume();
7353
+ }
7335
7354
  onFlushed(opts) {
7336
7355
  const frameNumber = opts.frameNumber;
7337
7356
  if (1 === frameNumber) this.emit("FIRST_FRAME_SENT");
@@ -7998,10 +8017,7 @@ const VIRTUAL_KEYWORDS = [
7998
8017
  "droidcam"
7999
8018
  ];
8000
8019
  function isVirtualCamera(videoTrack) {
8001
- const capabilities = videoTrack.getCapabilities();
8002
- if (!capabilities.frameRate) return true;
8003
- const isVirtual = VIRTUAL_KEYWORDS.some((keyword)=>videoTrack.label.toLowerCase().includes(keyword));
8004
- return isVirtual;
8020
+ return VIRTUAL_KEYWORDS.some((keyword)=>videoTrack.label.toLowerCase().includes(keyword));
8005
8021
  }
8006
8022
  const util_isVirtualCamera = isVirtualCamera;
8007
8023
  function userMedia_define_property(obj, key, value) {
@@ -8392,7 +8408,7 @@ class Recorder extends capture {
8392
8408
  let explanation = "(No explanation given)";
8393
8409
  if (command.args?.err?.message) explanation = command.args.err.message;
8394
8410
  const err = error_createError({
8395
- message: "Websocket error from Videomail server",
8411
+ message: "WebSocket error from the Videomail server",
8396
8412
  explanation,
8397
8413
  err: deserializeError(command.args?.err),
8398
8414
  options: this.options
@@ -9012,21 +9028,36 @@ class Visuals extends util_Despot {
9012
9028
  this.clearCameraRecoveryNotice();
9013
9029
  return this.recorder.recoverCamera();
9014
9030
  }
9015
- resume() {
9031
+ canResumeCountdown(restored) {
9032
+ return restored && Boolean(this.recorderInsides.isCountingDown());
9033
+ }
9034
+ async resumeCountdown() {
9035
+ const restored = await this.recoverCamera();
9036
+ if (!this.canResumeCountdown(restored)) return;
9037
+ this.recorder.resumeMediaForCountdown();
9038
+ this.recorderInsides.resumeCountdown();
9039
+ this.recorderInsides.hidePause();
9040
+ }
9041
+ async resume() {
9016
9042
  this.clearCameraRecoveryNotice();
9017
- if (this.recorderInsides.isCountingDown()) {
9018
- this.recorderInsides.resumeCountdown();
9019
- this.recorderInsides.hidePause();
9020
- } else {
9043
+ if (this.recorderInsides.isCountingDown()) await this.resumeCountdown();
9044
+ else {
9021
9045
  this.recorder.resume();
9022
9046
  if (!this.recorder.isPaused()) this.recorderInsides.hidePause();
9023
9047
  }
9024
9048
  }
9049
+ resumeFromControl() {
9050
+ this.resume().catch((exc)=>{
9051
+ this.emit("ERROR", {
9052
+ exc
9053
+ });
9054
+ });
9055
+ }
9025
9056
  pauseOrResume() {
9026
- if (this.cameraRecoveryFailed && this.recorder.isPaused()) this.resume();
9057
+ if (this.cameraRecoveryFailed && this.recorder.isPaused()) this.resumeFromControl();
9027
9058
  else if (this.isRecordable()) {
9028
9059
  if (this.isRecording()) this.pause();
9029
- else if (this.recorder.isPaused()) this.resume();
9060
+ else if (this.recorder.isPaused()) this.resumeFromControl();
9030
9061
  else if (this.recorder.isReady()) this.recorder.record();
9031
9062
  }
9032
9063
  }
@@ -9055,8 +9086,8 @@ class Visuals extends util_Despot {
9055
9086
  isPaused() {
9056
9087
  return this.recorder.isPaused();
9057
9088
  }
9058
- error(err) {
9059
- this.notifier.error(err);
9089
+ error(err, blocking = true) {
9090
+ this.notifier.error(err, blocking);
9060
9091
  }
9061
9092
  hide() {
9062
9093
  if (this.visualsElement) {
@@ -9165,6 +9196,7 @@ function container_define_property(obj, key, value) {
9165
9196
  else obj[key] = value;
9166
9197
  return obj;
9167
9198
  }
9199
+ const INTERACTIVE_SPACE_TARGETS = "button, input, select, textarea, a[href], summary, label, audio[controls], video[controls], [contenteditable]:not([contenteditable='false']), [role='button'], [role='link'], [role='checkbox'], [role='radio'], [role='switch'], [role='menuitem'], [role='tab'], [tabindex]:not([tabindex='-1'])";
9168
9200
  class Container extends util_Despot {
9169
9201
  buildChildren(playerOnly = false, parentElement) {
9170
9202
  const parentElementInfo = parentElement ? `, parentElement="${string_pretty(parentElement)}"` : "";
@@ -9236,9 +9268,9 @@ class Container extends util_Despot {
9236
9268
  if (params.exc.stack) this.options.logger.error(params.exc.stack);
9237
9269
  else if (params.exc.message) this.options.logger.error(params.exc.message);
9238
9270
  } else this.options.logger.error(params.exc);
9239
- if (this.options.displayErrors && params.err) this.visuals.error(params.err);
9240
- else if (this.options.displayErrors && params.exc && params.exc instanceof error_VideomailError) this.visuals.error(params.exc);
9241
- else this.visuals.reset();
9271
+ if (this.options.displayErrors && params.err) this.visuals.error(params.err, !params.recoverable);
9272
+ else if (this.options.displayErrors && params.exc && params.exc instanceof error_VideomailError) this.visuals.error(params.exc, !params.recoverable);
9273
+ else if (!params.recoverable) this.visuals.reset();
9242
9274
  }
9243
9275
  initEvents(playerOnly = false) {
9244
9276
  this.options.logger.debug(`Container: initEvents (playerOnly = ${playerOnly})`);
@@ -9256,7 +9288,7 @@ class Container extends util_Despot {
9256
9288
  }
9257
9289
  });
9258
9290
  if (this.options.enableSpace) {
9259
- if (!playerOnly) window.addEventListener("keydown", this.handleKeyDown);
9291
+ if (!playerOnly) this.containerElement?.addEventListener("keydown", this.handleKeyDown);
9260
9292
  }
9261
9293
  this.on("ERROR", (params)=>{
9262
9294
  this.processError(params);
@@ -9296,7 +9328,7 @@ class Container extends util_Despot {
9296
9328
  removeBrowserEventListeners() {
9297
9329
  window.removeEventListener("resize", this.handleWindowResize);
9298
9330
  window.removeEventListener("beforeunload", this.handleBeforeUnload);
9299
- window.removeEventListener("keydown", this.handleKeyDown);
9331
+ this.containerElement?.removeEventListener("keydown", this.handleKeyDown);
9300
9332
  this.stopListeningToVisibility?.();
9301
9333
  this.stopListeningToVisibility = void 0;
9302
9334
  }
@@ -9535,6 +9567,7 @@ class Container extends util_Despot {
9535
9567
  async submitAll(formData, method, url, hasHostAction = false) {
9536
9568
  let response;
9537
9569
  let hostResponse;
9570
+ let submissionFailed = false;
9538
9571
  const videomailKey = formData[this.options.selectors.keyInputName];
9539
9572
  try {
9540
9573
  const hasVideomailKey = Boolean(videomailKey);
@@ -9545,7 +9578,7 @@ class Container extends util_Despot {
9545
9578
  ].filter(Boolean).join(": ");
9546
9579
  this.options.logger.debug(`Container: submitAll(${output})`);
9547
9580
  this.beginWaiting();
9548
- if (this.options.disableFormWhenSubmitting) this.disableForm(true);
9581
+ if (this.options.disableFormWhenSubmitting) this.form?.disableForSubmission();
9549
9582
  this.emit("SUBMITTING");
9550
9583
  if (hasVideomailKey) {
9551
9584
  response = this.getPendingHostSubmissionResponse(videomailKey) ?? await this.submitVideomail(formData, method);
@@ -9575,15 +9608,18 @@ class Container extends util_Despot {
9575
9608
  });
9576
9609
  }
9577
9610
  } catch (exc) {
9611
+ submissionFailed = true;
9578
9612
  const err = error_createError({
9579
9613
  exc,
9580
9614
  options: this.options
9581
9615
  });
9582
9616
  this.emit("ERROR", {
9583
- err
9617
+ err,
9618
+ recoverable: true
9584
9619
  });
9585
9620
  } finally{
9586
9621
  const finalResponse = hostResponse ?? response;
9622
+ if (submissionFailed && this.options.disableFormWhenSubmitting) this.form?.restoreAfterFailedSubmission();
9587
9623
  if (finalResponse?.text && "text/html" === finalResponse.type) document.body.innerHTML = dompurify.sanitize(finalResponse.text);
9588
9624
  this.endWaiting();
9589
9625
  }
@@ -9624,7 +9660,7 @@ class Container extends util_Despot {
9624
9660
  }
9625
9661
  async submit() {
9626
9662
  this.options.logger.debug("Container: submit()");
9627
- if (this.lastValidation) return await this.form?.doTheSubmit();
9663
+ if (!this.options.enableAutoValidation || this.lastValidation) return await this.form?.doTheSubmit();
9628
9664
  return false;
9629
9665
  }
9630
9666
  isCountingDown() {
@@ -9637,7 +9673,11 @@ class Container extends util_Despot {
9637
9673
  this.visuals.record();
9638
9674
  }
9639
9675
  resume() {
9640
- this.visuals.resume();
9676
+ this.visuals.resume().catch((exc)=>{
9677
+ this.emit("ERROR", {
9678
+ exc
9679
+ });
9680
+ });
9641
9681
  }
9642
9682
  stop() {
9643
9683
  this.visuals.stop();
@@ -9657,14 +9697,16 @@ class Container extends util_Despot {
9657
9697
  e
9658
9698
  });
9659
9699
  }), container_define_property(this, "handleKeyDown", (e)=>{
9660
- const element = e.target;
9661
- const tagName = element.tagName;
9662
- const isEditable = element.isContentEditable || "true" === element.contentEditable;
9663
- if (!isEditable && tagName && "INPUT" !== tagName.toUpperCase() && "TEXTAREA" !== tagName.toUpperCase() && "Space" === e.code) {
9664
- e.preventDefault();
9665
- if (this.options.enablePause) this.visuals.pauseOrResume();
9666
- else this.visuals.recordOrStop();
9667
- }
9700
+ const containerElement = this.containerElement;
9701
+ if (!containerElement) return;
9702
+ const eventPath = e.composedPath();
9703
+ const targetContainerIndex = eventPath.findIndex((eventTarget)=>eventTarget instanceof Element && eventTarget.classList.contains(this.options.selectors.containerClass));
9704
+ const targetContainer = eventPath[targetContainerIndex];
9705
+ const isInteractiveTarget = eventPath.slice(0, targetContainerIndex + 1).some((eventTarget)=>eventTarget instanceof Element && eventTarget.matches(INTERACTIVE_SPACE_TARGETS));
9706
+ if (!eventPath.includes(containerElement) || targetContainer !== containerElement || isInteractiveTarget || e.defaultPrevented || e.repeat || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || "Space" !== e.code) return;
9707
+ e.preventDefault();
9708
+ if (this.options.enablePause) this.visuals.pauseOrResume();
9709
+ else this.visuals.recordOrStop();
9668
9710
  });
9669
9711
  this.visuals = new wrappers_visuals(this, options);
9670
9712
  this.buttons = new buttons(this, options);
@@ -14,6 +14,7 @@ export interface VideomailCameraRecoveryFailedParams {
14
14
  export interface VideomailErrorParams {
15
15
  exc?: unknown;
16
16
  err?: VideomailError;
17
+ recoverable?: boolean | undefined;
17
18
  }
18
19
  export interface VideomailRecordingParams {
19
20
  framesCount: number;
@@ -1,2 +1,2 @@
1
- declare function isVirtualCamera(videoTrack: MediaStreamTrack): boolean;
1
+ declare function isVirtualCamera(videoTrack: Pick<MediaStreamTrack, "label">): boolean;
2
2
  export default isVirtualCamera;
@@ -18,6 +18,7 @@ declare class Form extends Despot {
18
18
  private submitButtonFormAttribute;
19
19
  private generatedFormId;
20
20
  private isSubmitting;
21
+ private readonly submissionDisabledStates;
21
22
  private readonly FORM_FIELDS;
22
23
  constructor(container: Container, formElement: HTMLFormElement, options: VideomailClientOptions);
23
24
  private readonly validate;
@@ -406,6 +407,8 @@ declare class Form extends Despot {
406
407
  private getRegisteredFormElements;
407
408
  disable(buttonsToo: boolean): void;
408
409
  enable(buttonsToo: boolean): void;
410
+ disableForSubmission(): void;
411
+ restoreAfterFailedSubmission(): void;
409
412
  build(): void;
410
413
  private removeAllInputListeners;
411
414
  private hideSubmitButton;
@@ -31,7 +31,7 @@ declare class Notifier extends Despot {
31
31
  private show;
32
32
  private runEntertainment;
33
33
  private cancelEntertainment;
34
- error(err: VideomailError): void;
34
+ error(err: VideomailError, blocking?: boolean): void;
35
35
  private getMessageElement;
36
36
  private setMessage;
37
37
  private setExplanation;
@@ -66,6 +66,7 @@ declare abstract class RecorderCapture extends RecorderMedia {
66
66
  validate(): boolean;
67
67
  pause(params?: PauseParams): void;
68
68
  resume(): void;
69
+ resumeMediaForCountdown(): void;
69
70
  private onFlushed;
70
71
  private draw;
71
72
  private createLoop;
@@ -40,7 +40,10 @@ declare class Visuals extends Despot {
40
40
  }): void;
41
41
  private clearCameraRecoveryNotice;
42
42
  recoverCamera(): Promise<boolean>;
43
- resume(): void;
43
+ private canResumeCountdown;
44
+ private resumeCountdown;
45
+ resume(): Promise<void>;
46
+ private resumeFromControl;
44
47
  pauseOrResume(): void;
45
48
  recordOrStop(): void;
46
49
  getRecorder(): Recorder;
@@ -52,7 +55,7 @@ declare class Visuals extends Despot {
52
55
  } | undefined;
53
56
  getAudioSampleRate(): number | undefined;
54
57
  isPaused(): boolean | undefined;
55
- error(err: VideomailError): void;
58
+ error(err: VideomailError, blocking?: boolean): void;
56
59
  hide(): void;
57
60
  isHidden(): boolean;
58
61
  showVisuals(): void;