videomail-client 16.4.1 → 16.5.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/README.md CHANGED
@@ -13,9 +13,15 @@
13
13
  [netlify-image]: https://api.netlify.com/api/v1/badges/3c9df5b4-8b85-4081-950a-d5df2dbd9926/deploy-status
14
14
  [netlify-url]: https://app.netlify.com/sites/videomail-client/deploys
15
15
 
16
- Record webcam videos in contact forms.
16
+ Bring Sign Language to your contact forms. ✉
17
17
 
18
- The client captures image frames with `navigator.mediaDevices.getUserMedia()`, streams them to the Videomail service over WebSocket, and receives an encoded video. No browser plugins are required. The package includes ESM, CommonJS, UMD, and TypeScript declaration builds.
18
+ Record webcam videos without browser plugins:
19
+
20
+ - Capture frames with `navigator.mediaDevices.getUserMedia()`.
21
+ - Stream them to Videomail over WebSocket.
22
+ - Get an encoded video back.
23
+
24
+ Made for Deaf users, and for hearing users learning Sign Language. The package includes ESM, CommonJS, UMD, and TypeScript declaration builds.
19
25
 
20
26
  - [Live demo](#live-demo)
21
27
  - [Storybook examples](#storybook-examples)
@@ -36,9 +42,9 @@ Try it at [videomail-client.netlify.app](https://videomail-client.netlify.app).
36
42
 
37
43
  ### Real-world usage
38
44
 
39
- There is a full version with all its features on [videomail.io](https://videomail.io).
45
+ Try the full experience at [videomail.io](https://videomail.io).
40
46
 
41
- And there is more:
47
+ You can also find it on:
42
48
 
43
49
  - [https://wfdeaf.org/contact](https://wfdeaf.org/contact)
44
50
  - [https://www.deaf.org.nz/contact](https://www.deaf.org.nz/contact)
@@ -46,7 +52,7 @@ And there is more:
46
52
 
47
53
  ## Storybook examples
48
54
 
49
- To check out some examples in your browser locally, just run these two commands:
55
+ To try the examples locally:
50
56
 
51
57
  1. `npm install`
52
58
  2. `npm run storybook`
@@ -114,7 +120,7 @@ const videomailClient = new VideomailClient({
114
120
 
115
121
  ### videomailClient.on()
116
122
 
117
- `VideomailClient` provides an event-emitter-style API. `on()` returns an unsubscribe function:
123
+ Use `on()` to listen for events. It returns an unsubscribe function:
118
124
 
119
125
  ```ts
120
126
  videomailClient.on("FORM_READY", () => {
@@ -122,7 +128,7 @@ videomailClient.on("FORM_READY", () => {
122
128
  });
123
129
 
124
130
  videomailClient.on("SUBMITTED", ({ videomail, response }) => {
125
- // Continue with application-specific submission handling.
131
+ // Handle the submitted video in your app.
126
132
  });
127
133
  ```
128
134
 
@@ -132,13 +138,13 @@ Check them out at [src/types/events/index.ts](https://github.com/binarykitchen/v
132
138
 
133
139
  Some events include typed parameters exported by the package.
134
140
 
135
- The client includes default visual error handling. Applications can also subscribe to the `ERROR` event for custom logging or recovery.
141
+ The client shows errors by default. Listen for `ERROR` to add your own logging or recovery.
136
142
 
137
- Videomail errors extend the native `Error` class and include additional diagnostic data.
143
+ Videomail errors extend the native `Error` class with details for troubleshooting.
138
144
 
139
145
  ### videomailClient.show()
140
146
 
141
- Automatically fills the DOM with a form for video recording. By default the HTML element with the ID `videomail` will be filled, see options.
147
+ Adds the recording form to the page. By default, it uses the element with ID `videomail`. You can change this in the [options](#options).
142
148
 
143
149
  ### videomailClient.record()
144
150
 
@@ -146,19 +152,32 @@ Starts recording without requiring the user to press the record button.
146
152
 
147
153
  ### videomailClient.pause()
148
154
 
149
- Pauses an active recording or countdown without discarding it. Idle cameras and unsent previews are left alone. Useful for native applications. To resume, refer to the next function `videomailClient.recoverCamera()`.
155
+ Pauses a recording or countdown without losing it. Leaves idle cameras and unsent previews alone.
156
+
157
+ For native apps, pair this with `videomailClient.recoverCamera()` when the app returns to the foreground.
150
158
 
151
159
  ### videomailClient.recoverCamera()
152
160
 
153
- Returns a `Promise<boolean>` indicating whether camera recovery succeeds. It restores playback for live tracks or requests a replacement stream when camera or microphone tracks have ended. Duplicate calls share the pending recovery. An unbuilt client, unsent preview, encoding, or submission is left alone and returns `false`.
161
+ Returns a `Promise<boolean>`: `true` if camera recovery succeeds.
162
+
163
+ - Restarts playback for live tracks.
164
+ - Requests a new stream if camera or microphone tracks have ended.
165
+ - Shares pending recovery across duplicate calls.
166
+ - Returns `false` without changes if the client is unbuilt, has an unsent preview, is encoding, or is submitting.
167
+
168
+ Recovery keeps frame dimensions, frame/sample counts, and the audio sample rate. It does **not** resume recording or a countdown on its own. The user chooses Resume, which waits for recovery before sending more frames.
169
+
170
+ With automatic pause enabled, hiding the page pauses recording. Returning to it recovers the camera. Native apps should call `pause()` when backgrounded and `recoverCamera()` when foregrounded. Wire these into your app's lifecycle; no Capacitor dependency is needed. Use recovery, not `startOver()`, to keep a paused take.
154
171
 
155
- Recovery preserves captured frame dimensions, frame/sample counters, and the audio sample rate. Foreground recovery never resumes capture or a countdown automatically. The user must explicitly choose Resume; that action waits for recovery before sending more frames.
172
+ Recovery events:
156
173
 
157
- With automatic pause enabled, browser visibility changes pause capture and recover the camera on return. Native hosts should call `pause()` on background and `recoverCamera()` on foreground through their own lifecycle integration. The client has no Capacitor dependency. Do not call `startOver()` to recover a paused take.
174
+ - `CAMERA_RECOVERING`: recovery has started.
175
+ - `USER_MEDIA_READY` with `recovering: true`: the replacement stream is ready.
176
+ - `CAMERA_RECOVERY_FAILED` with an `err`: access, playback, audio setup, or the recovery deadline failed.
158
177
 
159
- `CAMERA_RECOVERING` signals the start of recovery. `USER_MEDIA_READY` includes `recovering: true` after a replacement stream is initialized. `CAMERA_RECOVERY_FAILED` provides an `err` when access, playback, audio initialization, or the recovery deadline fails. The default notification does not reset the take; the user can retry Resume or stop to keep the recorded part. Stop, reset, unload, and submission cancel pending recovery, and late streams are stopped.
178
+ The default failure notice keeps the take. Users can retry Resume or stop to keep what they recorded. Stop, reset, unload, and submission cancel pending recovery. Streams that arrive after cancellation are stopped.
160
179
 
161
- This does not reconnect a lost recording WebSocket or survive process termination. Physical-device camera and microphone validation remains necessary.
180
+ Recovery cannot reconnect a lost recording WebSocket or keep a take after the app process ends. Test the camera and microphone on physical devices, too.
162
181
 
163
182
  ### videomailClient.replay(videomail[, parentElementId])
164
183
 
@@ -166,13 +185,13 @@ Adds a video player for the supplied videomail.
166
185
 
167
186
  If `replayParentElementId` is supplied, the player is inserted into that element. Otherwise, the client uses or creates a replay container within the configured container.
168
187
 
169
- Also note that, when the parent element already contains a video container like this
188
+ If the parent already has a video element like this:
170
189
 
171
190
  ```html
172
191
  <video class="replay"></video>
173
192
  ```
174
193
 
175
- the client reuses it instead of creating another DOM element.
194
+ The client reuses it. No extra element needed.
176
195
 
177
196
  ### videomailClient.startOver()
178
197
 
@@ -180,10 +199,10 @@ Resets the client and returns it to the ready state so the same instance can rec
180
199
 
181
200
  ### videomailClient.getByAlias(alias)
182
201
 
183
- Returns a videomail asynchronously for the given alias. You can obtain the alias from:
202
+ Returns a videomail asynchronously for the given alias. Find the alias in:
184
203
 
185
- 1. The form submission to your own server has it under `videomail_alias` in the form body.
186
- 2. The `SUBMITTED` event payload.
204
+ 1. The `videomail_alias` field sent to your server.
205
+ 2. The `SUBMITTED` event data.
187
206
 
188
207
  ### videomailClient.getByKey(key)
189
208
 
@@ -199,15 +218,15 @@ Returns the videomail thread containing the given key.
199
218
 
200
219
  ### videomailClient.unload()
201
220
 
202
- Manually unloads the webcam, closes the active WebSocket connection, and removes all internal event listeners.
221
+ Stops the webcam, closes the active WebSocket connection, and removes all internal event listeners.
203
222
 
204
223
  ### videomailClient.hide()
205
224
 
206
- Hides all the visuals (but does not unload anything).
225
+ Hides the UI without unloading it.
207
226
 
208
227
  ### videomailClient.isDirty()
209
228
 
210
- Returns `true` when a video has been recorded but not submitted. This can be used before navigation to warn about an unsent recording.
229
+ Returns `true` when a recorded video has not been submitted. Use it to warn users before they leave an unsent recording.
211
230
 
212
231
  ### videomailClient.isRecording()
213
232
 
@@ -219,21 +238,25 @@ Returns `true` after the client UI has been built and before it is unloaded.
219
238
 
220
239
  ### videomailClient.submit()
221
240
 
222
- Manually triggers submission when the client and form are valid. This is useful when another UI layer owns the visible submit control.
241
+ Submits the form after client validation succeeds.
242
+
243
+ With `enableAutoValidation: false`, no client validation event is needed. Your app must validate the form first. This helps when your app provides its own submit button.
223
244
 
224
245
  ### videomailClient.getLogLines()
225
246
 
226
- Returns the recently collected log lines when the configured logger supports collection.
247
+ Returns recent log lines if your logger collects them.
227
248
 
228
249
  ### videomailClient.setLimitSeconds(limitSeconds)
229
250
 
230
- Updates the recording time limit for subsequent recording activity.
251
+ Changes the time limit for further recording.
231
252
 
232
253
  ## Stored videomail data
233
254
 
234
- The `SUBMITTED` event includes a `videomail` object. The exact response can evolve, but its shape follows the exported `Videomail` type. A shortened example is shown below:
255
+ The `SUBMITTED` event includes a `videomail` object. Its fields may evolve; check the exported `Videomail` type for the current shape.
256
+
257
+ For new recordings, `width` and `height` describe the captured canvas frames. They are not the viewport or resized preview dimensions. They stay available after the camera stops and are replaced when you record again.
235
258
 
236
- For new recordings, submitted `width` and `height` describe the captured canvas frames, not the browser viewport or the resized preview. These dimensions survive stopping the camera and are replaced when recording again.
259
+ Here's a shortened example:
237
260
 
238
261
  ```json
239
262
  {
@@ -276,7 +299,7 @@ You can also retrieve this data with `videomailClient.getByKey()`.
276
299
 
277
300
  ## Form Submissions
278
301
 
279
- How to configure, inject meta data and test form submissions with the Videomail client can be found in [Form Submissions ✏️](./docs/FORM_SUBMISSIONS.md).
302
+ See [Form Submissions ✏️](./docs/FORM_SUBMISSIONS.md) to set up submissions, include metadata, and test your integration.
280
303
 
281
304
  ## Privacy and error reporting
282
305
 
@@ -284,13 +307,26 @@ Read about our privacy and error reporting practices in [Privacy and error repor
284
307
 
285
308
  ## Whitelist
286
309
 
287
- Examples work at [https://localhost:8443](https://localhost:8443) because localhost is allowed by the remote Videomail server. `https://localhost` and `https://localhost:443` are also available for local development. Other origins require their own whitelist entry.
310
+ The examples work locally without extra setup. Videomail allows these development origins:
311
+
312
+ - [https://localhost:8443](https://localhost:8443)
313
+ - `https://localhost`
314
+ - `https://localhost:443`
315
+
316
+ Other origins need their own whitelist entry.
288
317
 
289
318
  For a deployed domain, request access at [videomail.io/whitelist](https://videomail.io/whitelist). You will receive a whitelist key for the approved origins.
290
319
 
291
320
  ## Browser compatibility
292
321
 
293
- Recording requires a secure context (`https://` or localhost) and support for `navigator.mediaDevices.getUserMedia()`, WebSocket, Canvas, and AudioWorklet when audio is enabled. Current evergreen desktop and mobile browsers are supported. Internet Explorer is not supported.
322
+ Recording needs a secure context (`https://` or localhost), plus:
323
+
324
+ - `navigator.mediaDevices.getUserMedia()`
325
+ - WebSocket
326
+ - Canvas
327
+ - AudioWorklet, if audio is enabled
328
+
329
+ Current evergreen desktop and mobile browsers are supported. Internet Explorer is not.
294
330
 
295
331
  See [Can I Use: Media Capture from DOM Elements](https://caniuse.com/stream) and test the [live demo](#live-demo) in the browsers required by your integration.
296
332
 
@@ -304,7 +340,7 @@ It extends the Ninja Forms form builder with a webcam input and submission integ
304
340
 
305
341
  ### Changelog
306
342
 
307
- A separate changelog is not maintained. Use `git log` or the [commit history](https://github.com/binarykitchen/videomail-client/commits/master).
343
+ No separate changelog. Check `git log` or the [commit history](https://github.com/binarykitchen/videomail-client/commits/master).
308
344
 
309
345
  ### Noise
310
346
 
@@ -316,7 +352,7 @@ Videomail in the wild:
316
352
 
317
353
  This is just the beginning. I will add a lot more over time.
318
354
 
319
- Bear with me, there are lots of problems to crack, especially with the performance, audio part and some unit tests are missing. I do not want to waste too much time on perfection unless it's proven to work then I rewrite piece by piece.
355
+ There's still work to do on performance, audio, and test coverage. We improve things piece by piece, rather than chase perfection in one big rewrite.
320
356
 
321
357
  ### Credits
322
358
 
@@ -336,8 +372,8 @@ They all deserve lots of love in return. Thank you so much.
336
372
 
337
373
  ### Code quality
338
374
 
339
- The project prioritizes stability and bug fixes over large rewrites. Its implementation has evolved several times as browser media APIs and integration requirements have changed.
375
+ Stability and bug fixes come before big rewrites. The code keeps evolving with browser media APIs and the apps that use it.
340
376
 
341
377
  ### Final philosophy
342
378
 
343
- The primary goal is to make Sign Language easier to use in email and web forms.
379
+ Make Sign Language at home in email and web forms. That's what we're here for.
@@ -1,11 +1,11 @@
1
1
  var __webpack_modules__ = {
2
- pJ (module, __webpack_exports__, __webpack_require__) {
2
+ eq (module, __webpack_exports__, __webpack_require__) {
3
3
  "use strict";
4
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1 = __webpack_require__("K7");
5
- 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);
6
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0 = __webpack_require__("Ly");
7
- 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);
8
- 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());
4
+ var _node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1 = __webpack_require__("erX");
5
+ 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);
6
+ var _node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0 = __webpack_require__("zm");
7
+ 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);
8
+ 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());
9
9
  ___CSS_LOADER_EXPORT___.push([
10
10
  module.id,
11
11
  `@keyframes blink {
@@ -153,7 +153,7 @@ var __webpack_modules__ = {
153
153
  });
154
154
  },
155
155
  b6 (module, exports1, __webpack_require__) {
156
- var EventEmitter = __webpack_require__("qU").EventEmitter, inherits = __webpack_require__("c5"), raf = __webpack_require__("jY"), methods;
156
+ var EventEmitter = __webpack_require__("q").EventEmitter, inherits = __webpack_require__("c5"), raf = __webpack_require__("jY"), methods;
157
157
  var defaultRAFObject = {
158
158
  requestAnimationFrame: raf,
159
159
  cancelAnimationFrame: raf.cancel
@@ -1831,7 +1831,7 @@ var __webpack_modules__ = {
1831
1831
  },
1832
1832
  xF (module, __unused_rspack_exports, __webpack_require__) {
1833
1833
  "use strict";
1834
- var document1 = __webpack_require__("gM");
1834
+ var document1 = __webpack_require__("g");
1835
1835
  var Event1 = __webpack_require__("cE");
1836
1836
  var Keys = __webpack_require__("Dy");
1837
1837
  module.exports = Visibility;
@@ -2186,7 +2186,7 @@ var __webpack_modules__ = {
2186
2186
  var isArray = __webpack_require__("ab");
2187
2187
  var Duplex;
2188
2188
  Readable.ReadableState = ReadableState;
2189
- __webpack_require__("qU").EventEmitter;
2189
+ __webpack_require__("q").EventEmitter;
2190
2190
  var EElistenerCount = function(emitter, type) {
2191
2191
  return emitter.listeners(type).length;
2192
2192
  };
@@ -3450,7 +3450,7 @@ var __webpack_modules__ = {
3450
3450
  };
3451
3451
  },
3452
3452
  tb (module, __unused_rspack_exports, __webpack_require__) {
3453
- module.exports = __webpack_require__("qU").EventEmitter;
3453
+ module.exports = __webpack_require__("q").EventEmitter;
3454
3454
  },
3455
3455
  GB (module, exports1, __webpack_require__) {
3456
3456
  exports1 = module.exports = __webpack_require__("rp");
@@ -3847,7 +3847,7 @@ var __webpack_modules__ = {
3847
3847
  "use strict";
3848
3848
  module.exports = Object;
3849
3849
  },
3850
- qU (module) {
3850
+ q (module) {
3851
3851
  "use strict";
3852
3852
  var R = 'object' == typeof Reflect ? Reflect : null;
3853
3853
  var ReflectApply = R && 'function' == typeof R.apply ? R.apply : function(target, receiver, args) {
@@ -4897,7 +4897,7 @@ var __webpack_modules__ = {
4897
4897
  return tuple.listen;
4898
4898
  }
4899
4899
  },
4900
- gM (module, __unused_rspack_exports, __webpack_require__) {
4900
+ g (module, __unused_rspack_exports, __webpack_require__) {
4901
4901
  var topLevel = void 0 !== __webpack_require__.g ? __webpack_require__.g : "u" > typeof window ? window : {};
4902
4902
  var minDoc = __webpack_require__("MM");
4903
4903
  var doccy;
@@ -8811,7 +8811,7 @@ var __webpack_modules__ = {
8811
8811
  var isArray = __webpack_require__("N3");
8812
8812
  var Duplex;
8813
8813
  Readable.ReadableState = ReadableState;
8814
- __webpack_require__("qU").EventEmitter;
8814
+ __webpack_require__("q").EventEmitter;
8815
8815
  var EElistenerCount = function(emitter, type) {
8816
8816
  return emitter.listeners(type).length;
8817
8817
  };
@@ -8830,7 +8830,7 @@ var __webpack_modules__ = {
8830
8830
  var debug = void 0;
8831
8831
  debug = debugUtil && debugUtil.debuglog ? debugUtil.debuglog('stream') : function() {};
8832
8832
  var BufferList = __webpack_require__("aI");
8833
- var destroyImpl = __webpack_require__("R");
8833
+ var destroyImpl = __webpack_require__("R5");
8834
8834
  var StringDecoder;
8835
8835
  util.inherits(Readable, Stream);
8836
8836
  var kProxyEvents = [
@@ -9565,7 +9565,7 @@ var __webpack_modules__ = {
9565
9565
  function _isUint8Array(obj) {
9566
9566
  return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
9567
9567
  }
9568
- var destroyImpl = __webpack_require__("R");
9568
+ var destroyImpl = __webpack_require__("R5");
9569
9569
  util.inherits(Writable, Stream);
9570
9570
  function nop() {}
9571
9571
  function WritableState(options, stream) {
@@ -10019,7 +10019,7 @@ var __webpack_modules__ = {
10019
10019
  return this.constructor.name + ' ' + obj;
10020
10020
  };
10021
10021
  },
10022
- R (module, __unused_rspack_exports, __webpack_require__) {
10022
+ R5 (module, __unused_rspack_exports, __webpack_require__) {
10023
10023
  "use strict";
10024
10024
  var pna = __webpack_require__("sj");
10025
10025
  function destroy(err, cb) {
@@ -10075,7 +10075,7 @@ var __webpack_modules__ = {
10075
10075
  };
10076
10076
  },
10077
10077
  O (module, __unused_rspack_exports, __webpack_require__) {
10078
- module.exports = __webpack_require__("qU").EventEmitter;
10078
+ module.exports = __webpack_require__("q").EventEmitter;
10079
10079
  },
10080
10080
  Fo (module, exports1, __webpack_require__) {
10081
10081
  exports1 = module.exports = __webpack_require__("w");
@@ -10565,7 +10565,7 @@ var __webpack_modules__ = {
10565
10565
  a () {},
10566
10566
  Av () {},
10567
10567
  eD () {},
10568
- Ly (module) {
10568
+ zm (module) {
10569
10569
  "use strict";
10570
10570
  module.exports = function(cssWithMappingToString) {
10571
10571
  var list = [];
@@ -10619,13 +10619,13 @@ var __webpack_modules__ = {
10619
10619
  return list;
10620
10620
  };
10621
10621
  },
10622
- K7 (module) {
10622
+ erX (module) {
10623
10623
  "use strict";
10624
10624
  module.exports = function(i) {
10625
10625
  return i[1];
10626
10626
  };
10627
10627
  },
10628
- q (module) {
10628
+ R (module) {
10629
10629
  "use strict";
10630
10630
  var stylesInDOM = [];
10631
10631
  function getIndexByIdentifier(identifier) {
@@ -10704,7 +10704,7 @@ var __webpack_modules__ = {
10704
10704
  };
10705
10705
  };
10706
10706
  },
10707
- f (module) {
10707
+ uZ (module) {
10708
10708
  "use strict";
10709
10709
  var memo = {};
10710
10710
  function getTarget(target) {
@@ -10726,7 +10726,7 @@ var __webpack_modules__ = {
10726
10726
  }
10727
10727
  module.exports = insertBySelector;
10728
10728
  },
10729
- z7 (module) {
10729
+ mK (module) {
10730
10730
  "use strict";
10731
10731
  function insertStyleElement(options) {
10732
10732
  var element = document.createElement("style");
@@ -10736,7 +10736,7 @@ var __webpack_modules__ = {
10736
10736
  }
10737
10737
  module.exports = insertStyleElement;
10738
10738
  },
10739
- g (module, __unused_rspack_exports, __webpack_require__) {
10739
+ kU (module, __unused_rspack_exports, __webpack_require__) {
10740
10740
  "use strict";
10741
10741
  function setAttributesWithoutAttributes(styleElement) {
10742
10742
  var nonce = __webpack_require__.nc;
@@ -10744,7 +10744,7 @@ var __webpack_modules__ = {
10744
10744
  }
10745
10745
  module.exports = setAttributesWithoutAttributes;
10746
10746
  },
10747
- V (module) {
10747
+ Bd (module) {
10748
10748
  "use strict";
10749
10749
  function apply(styleElement, options, obj) {
10750
10750
  var css = "";
@@ -10781,7 +10781,7 @@ var __webpack_modules__ = {
10781
10781
  }
10782
10782
  module.exports = domAPI;
10783
10783
  },
10784
- AD (module) {
10784
+ snK (module) {
10785
10785
  "use strict";
10786
10786
  function styleTagTransform(css, styleElement) {
10787
10787
  if (styleElement.styleSheet) styleElement.styleSheet.cssText = css;
@@ -11126,7 +11126,7 @@ var __webpack_exports__ = {};
11126
11126
  var client = __webpack_require__("Q");
11127
11127
  var client_default = /*#__PURE__*/ __webpack_require__.n(client);
11128
11128
  var package_namespaceObject = {
11129
- rE: "16.4.1"
11129
+ rE: "16.5.0"
11130
11130
  };
11131
11131
  function isAudioEnabled(options) {
11132
11132
  return Boolean(options.audio.enabled);
@@ -14656,12 +14656,12 @@ var __webpack_exports__ = {};
14656
14656
  const errName = null != (_ref = null == err ? void 0 : err.name) ? _ref : null == err ? void 0 : err.constructor.name;
14657
14657
  switch(errName){
14658
14658
  case error_VideomailError.SECURITY_ERROR:
14659
- message = "The operation was insecure";
14660
- explanation = "Probably you have disallowed Cookies for this page?";
14659
+ message = "Your browser blocked this action";
14660
+ explanation = "Check this page's camera permissions and security settings.";
14661
14661
  classList.push(error_VideomailError.BROWSER_PROBLEM);
14662
14662
  break;
14663
14663
  case error_VideomailError.OVERCONSTRAINED:
14664
- message = "Invalid webcam constraints";
14664
+ message = "Your webcam cannot use these settings";
14665
14665
  if (err && "constraint" in err) {
14666
14666
  const overconstrainedError = err;
14667
14667
  const constraint = overconstrainedError.constraint;
@@ -14672,64 +14672,64 @@ var __webpack_exports__ = {};
14672
14672
  break;
14673
14673
  case "MediaDeviceFailedDueToShutdown":
14674
14674
  message = "Webcam is shutting down";
14675
- explanation = "This happens your webcam is already switching off and not giving you permission to use it.";
14675
+ explanation = "Wait for your webcam to finish switching off, then try again.";
14676
14676
  break;
14677
14677
  case "SourceUnavailableError":
14678
- message = "Source of your webcam cannot be accessed";
14679
- explanation = "Probably it is locked from another process or has a hardware error.";
14678
+ message = "Cannot access your webcam";
14679
+ explanation = "Another app may be using it, or there may be a hardware problem.";
14680
14680
  break;
14681
14681
  case "NO_DEVICES_FOUND":
14682
14682
  if (audioEnabled) {
14683
- message = "No webcam nor microphone found";
14684
- explanation = "Your browser cannot find a webcam with microphone attached to your machine.";
14683
+ message = "No webcam or microphone found";
14684
+ explanation = "Check that your webcam and microphone are connected.";
14685
14685
  } else {
14686
14686
  message = "No webcam found";
14687
- explanation = "Your browser cannot find a webcam attached to your machine.";
14687
+ explanation = "Check that your webcam is connected.";
14688
14688
  }
14689
14689
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14690
14690
  break;
14691
14691
  case "PermissionDismissedError":
14692
- message = "Ooops, you didn't give me any permissions?";
14693
- explanation = "Looks like you skipped the webcam permission dialogue.<br/>Please grant access next time the dialogue appears.";
14692
+ message = "Camera permission is needed";
14693
+ explanation = "The camera permission prompt was closed.<br/>Please allow access when it appears again.";
14694
14694
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14695
14695
  break;
14696
14696
  case error_VideomailError.NOT_ALLOWED_ERROR:
14697
14697
  case error_VideomailError.PERMISSION_DENIED:
14698
14698
  case "PermissionDeniedError":
14699
14699
  message = "Permission denied";
14700
- 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.";
14700
+ 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>";
14701
14701
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14702
14702
  break;
14703
14703
  case "HARDWARE_UNAVAILABLE":
14704
14704
  case "AbortError":
14705
14705
  message = "Webcam is unavailable";
14706
- explanation = "Maybe it is already busy in another window?";
14706
+ explanation = "Another window may be using it. Close it and try again.";
14707
14707
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14708
14708
  break;
14709
14709
  case "NO_VIDEO_FEED":
14710
- message = "No video feed found!";
14711
- explanation = "Your webcam is already used in another browser.";
14710
+ message = "No video feed found";
14711
+ explanation = "Another browser may be using your webcam.";
14712
14712
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14713
14713
  break;
14714
14714
  case error_VideomailError.STARTING_FAILED:
14715
- message = "Starting video failed";
14716
- explanation = "Most likely this happens when the webcam is already active in another browser";
14715
+ message = "Could not start recording";
14716
+ explanation = "Another browser may be using your webcam.";
14717
14717
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14718
14718
  break;
14719
14719
  case "DevicesNotFoundError":
14720
- message = "No available webcam could be found";
14721
- explanation = "Looks like you do not have any webcam attached to your machine; or the one you plugged in is already used.";
14720
+ message = "No available webcam found";
14721
+ explanation = "Check that your webcam is connected and not being used by another app.";
14722
14722
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14723
14723
  break;
14724
14724
  case error_VideomailError.NOT_READABLE_ERROR:
14725
14725
  case error_VideomailError.TRACK_START_ERROR:
14726
- message = "No access to webcam";
14727
- explanation = "Perhaps you are already using it in another browser?";
14726
+ message = "Cannot access your webcam";
14727
+ explanation = "Another browser may be using it. Close it and try again.";
14728
14728
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14729
14729
  break;
14730
14730
  case error_VideomailError.INVALID_STATE_ERROR:
14731
- message = "Invalid state";
14732
- explanation = "Video recording stream from your webcam already has finished";
14731
+ message = "Your camera stream has ended";
14732
+ explanation = "The webcam stream is no longer active.";
14733
14733
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14734
14734
  break;
14735
14735
  case error_VideomailError.DOM_EXCEPTION:
@@ -15832,19 +15832,19 @@ var __webpack_exports__ = {};
15832
15832
  return newOptions;
15833
15833
  }
15834
15834
  const options_mergeWithDefaultOptions = mergeWithDefaultOptions;
15835
- var injectStylesIntoStyleTag = __webpack_require__("q");
15835
+ var injectStylesIntoStyleTag = __webpack_require__("R");
15836
15836
  var injectStylesIntoStyleTag_default = /*#__PURE__*/ __webpack_require__.n(injectStylesIntoStyleTag);
15837
- var styleDomAPI = __webpack_require__("V");
15837
+ var styleDomAPI = __webpack_require__("Bd");
15838
15838
  var styleDomAPI_default = /*#__PURE__*/ __webpack_require__.n(styleDomAPI);
15839
- var insertBySelector = __webpack_require__("f");
15839
+ var insertBySelector = __webpack_require__("uZ");
15840
15840
  var insertBySelector_default = /*#__PURE__*/ __webpack_require__.n(insertBySelector);
15841
- var setAttributesWithoutAttributes = __webpack_require__("g");
15841
+ var setAttributesWithoutAttributes = __webpack_require__("kU");
15842
15842
  var setAttributesWithoutAttributes_default = /*#__PURE__*/ __webpack_require__.n(setAttributesWithoutAttributes);
15843
- var insertStyleElement = __webpack_require__("z7");
15843
+ var insertStyleElement = __webpack_require__("mK");
15844
15844
  var insertStyleElement_default = /*#__PURE__*/ __webpack_require__.n(insertStyleElement);
15845
- var styleTagTransform = __webpack_require__("AD");
15845
+ var styleTagTransform = __webpack_require__("snK");
15846
15846
  var styleTagTransform_default = /*#__PURE__*/ __webpack_require__.n(styleTagTransform);
15847
- var main = __webpack_require__("pJ");
15847
+ var main = __webpack_require__("eq");
15848
15848
  var main_options = {};
15849
15849
  main_options.styleTagTransform = styleTagTransform_default();
15850
15850
  main_options.setAttributes = setAttributesWithoutAttributes_default();
@@ -21274,10 +21274,7 @@ var __webpack_exports__ = {};
21274
21274
  "droidcam"
21275
21275
  ];
21276
21276
  function isVirtualCamera(videoTrack) {
21277
- const capabilities = videoTrack.getCapabilities();
21278
- if (!capabilities.frameRate) return true;
21279
- const isVirtual = VIRTUAL_KEYWORDS.some((keyword)=>videoTrack.label.toLowerCase().includes(keyword));
21280
- return isVirtual;
21277
+ return VIRTUAL_KEYWORDS.some((keyword)=>videoTrack.label.toLowerCase().includes(keyword));
21281
21278
  }
21282
21279
  const util_isVirtualCamera = isVirtualCamera;
21283
21280
  function userMedia_asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
@@ -21721,7 +21718,7 @@ var __webpack_exports__ = {};
21721
21718
  let explanation = "(No explanation given)";
21722
21719
  if (null == (_command_args = command.args) ? void 0 : null == (_command_args_err = _command_args.err) ? void 0 : _command_args_err.message) explanation = command.args.err.message;
21723
21720
  const err = error_createError({
21724
- message: "Websocket error from Videomail server",
21721
+ message: "WebSocket error from the Videomail server",
21725
21722
  explanation,
21726
21723
  err: deserializeError(null == (_command_args1 = command.args) ? void 0 : _command_args1.err),
21727
21724
  options: this.options
@@ -23031,7 +23028,7 @@ var __webpack_exports__ = {};
23031
23028
  submit() {
23032
23029
  return container_async_to_generator(function*() {
23033
23030
  this.options.logger.debug("Container: submit()");
23034
- if (this.lastValidation) {
23031
+ if (!this.options.enableAutoValidation || this.lastValidation) {
23035
23032
  var _this_form;
23036
23033
  return yield null == (_this_form = this.form) ? void 0 : _this_form.doTheSubmit();
23037
23034
  }
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.5.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:
@@ -4855,18 +4855,18 @@ function mergeWithDefaultOptions(options = {}) {
4855
4855
  return newOptions;
4856
4856
  }
4857
4857
  const options_mergeWithDefaultOptions = mergeWithDefaultOptions;
4858
- const main_0 = __webpack_require__("pJ");
4859
- const styleTagTransform = __webpack_require__("AD");
4858
+ const main_0 = __webpack_require__("eq");
4859
+ const styleTagTransform = __webpack_require__("snK");
4860
4860
  var styleTagTransform_default = /*#__PURE__*/ __webpack_require__.n(styleTagTransform);
4861
- const setAttributesWithoutAttributes = __webpack_require__("g2");
4861
+ const setAttributesWithoutAttributes = __webpack_require__("kU");
4862
4862
  var setAttributesWithoutAttributes_default = /*#__PURE__*/ __webpack_require__.n(setAttributesWithoutAttributes);
4863
- const insertBySelector = __webpack_require__("fR");
4863
+ const insertBySelector = __webpack_require__("uZ");
4864
4864
  var insertBySelector_default = /*#__PURE__*/ __webpack_require__.n(insertBySelector);
4865
- const styleDomAPI = __webpack_require__("Vq");
4865
+ const styleDomAPI = __webpack_require__("Bd");
4866
4866
  var styleDomAPI_default = /*#__PURE__*/ __webpack_require__.n(styleDomAPI);
4867
- const insertStyleElement = __webpack_require__("z7");
4867
+ const insertStyleElement = __webpack_require__("mK");
4868
4868
  var insertStyleElement_default = /*#__PURE__*/ __webpack_require__.n(insertStyleElement);
4869
- const injectStylesIntoStyleTag = __webpack_require__("qB");
4869
+ const injectStylesIntoStyleTag = __webpack_require__("RR");
4870
4870
  var injectStylesIntoStyleTag_default = /*#__PURE__*/ __webpack_require__.n(injectStylesIntoStyleTag);
4871
4871
  var main_options = {};
4872
4872
  main_options.styleTagTransform = styleTagTransform_default();
@@ -7998,10 +7998,7 @@ const VIRTUAL_KEYWORDS = [
7998
7998
  "droidcam"
7999
7999
  ];
8000
8000
  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;
8001
+ return VIRTUAL_KEYWORDS.some((keyword)=>videoTrack.label.toLowerCase().includes(keyword));
8005
8002
  }
8006
8003
  const util_isVirtualCamera = isVirtualCamera;
8007
8004
  function userMedia_define_property(obj, key, value) {
@@ -8392,7 +8389,7 @@ class Recorder extends capture {
8392
8389
  let explanation = "(No explanation given)";
8393
8390
  if (command.args?.err?.message) explanation = command.args.err.message;
8394
8391
  const err = error_createError({
8395
- message: "Websocket error from Videomail server",
8392
+ message: "WebSocket error from the Videomail server",
8396
8393
  explanation,
8397
8394
  err: deserializeError(command.args?.err),
8398
8395
  options: this.options
@@ -9624,7 +9621,7 @@ class Container extends util_Despot {
9624
9621
  }
9625
9622
  async submit() {
9626
9623
  this.options.logger.debug("Container: submit()");
9627
- if (this.lastValidation) return await this.form?.doTheSubmit();
9624
+ if (!this.options.enableAutoValidation || this.lastValidation) return await this.form?.doTheSubmit();
9628
9625
  return false;
9629
9626
  }
9630
9627
  isCountingDown() {
@@ -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;
package/dist/umd/index.js CHANGED
@@ -5,13 +5,13 @@
5
5
  else root["VideomailClient"] = factory();
6
6
  })(globalThis, ()=>(()=>{
7
7
  var __webpack_modules__ = {
8
- pJ (module1, __webpack_exports__, __webpack_require__) {
8
+ eq (module1, __webpack_exports__, __webpack_require__) {
9
9
  "use strict";
10
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1 = __webpack_require__("K7");
11
- 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);
12
- var _node_modules_rslib_core_node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0 = __webpack_require__("Ly");
13
- 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);
14
- 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());
10
+ var _node_modules_rsbuild_core_compiled_css_loader_noSourceMaps_js__rspack_import_1 = __webpack_require__("erX");
11
+ 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);
12
+ var _node_modules_rsbuild_core_compiled_css_loader_api_js__rspack_import_0 = __webpack_require__("zm");
13
+ 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);
14
+ 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());
15
15
  ___CSS_LOADER_EXPORT___.push([
16
16
  module1.id,
17
17
  `@keyframes blink {
@@ -159,7 +159,7 @@
159
159
  });
160
160
  },
161
161
  b6 (module1, exports1, __webpack_require__) {
162
- var EventEmitter = __webpack_require__("qU").EventEmitter, inherits = __webpack_require__("c5"), raf = __webpack_require__("jY"), methods;
162
+ var EventEmitter = __webpack_require__("q").EventEmitter, inherits = __webpack_require__("c5"), raf = __webpack_require__("jY"), methods;
163
163
  var defaultRAFObject = {
164
164
  requestAnimationFrame: raf,
165
165
  cancelAnimationFrame: raf.cancel
@@ -1837,7 +1837,7 @@
1837
1837
  },
1838
1838
  xF (module1, __unused_rspack_exports, __webpack_require__) {
1839
1839
  "use strict";
1840
- var document1 = __webpack_require__("gM");
1840
+ var document1 = __webpack_require__("g");
1841
1841
  var Event1 = __webpack_require__("cE");
1842
1842
  var Keys = __webpack_require__("Dy");
1843
1843
  module1.exports = Visibility;
@@ -2192,7 +2192,7 @@
2192
2192
  var isArray = __webpack_require__("ab");
2193
2193
  var Duplex;
2194
2194
  Readable.ReadableState = ReadableState;
2195
- __webpack_require__("qU").EventEmitter;
2195
+ __webpack_require__("q").EventEmitter;
2196
2196
  var EElistenerCount = function(emitter, type) {
2197
2197
  return emitter.listeners(type).length;
2198
2198
  };
@@ -3456,7 +3456,7 @@
3456
3456
  };
3457
3457
  },
3458
3458
  tb (module1, __unused_rspack_exports, __webpack_require__) {
3459
- module1.exports = __webpack_require__("qU").EventEmitter;
3459
+ module1.exports = __webpack_require__("q").EventEmitter;
3460
3460
  },
3461
3461
  GB (module1, exports1, __webpack_require__) {
3462
3462
  exports1 = module1.exports = __webpack_require__("rp");
@@ -3853,7 +3853,7 @@
3853
3853
  "use strict";
3854
3854
  module1.exports = Object;
3855
3855
  },
3856
- qU (module1) {
3856
+ q (module1) {
3857
3857
  "use strict";
3858
3858
  var R = 'object' == typeof Reflect ? Reflect : null;
3859
3859
  var ReflectApply = R && 'function' == typeof R.apply ? R.apply : function(target, receiver, args) {
@@ -4903,7 +4903,7 @@
4903
4903
  return tuple.listen;
4904
4904
  }
4905
4905
  },
4906
- gM (module1, __unused_rspack_exports, __webpack_require__) {
4906
+ g (module1, __unused_rspack_exports, __webpack_require__) {
4907
4907
  var topLevel = void 0 !== __webpack_require__.g ? __webpack_require__.g : "u" > typeof window ? window : {};
4908
4908
  var minDoc = __webpack_require__("MM");
4909
4909
  var doccy;
@@ -8817,7 +8817,7 @@
8817
8817
  var isArray = __webpack_require__("N3");
8818
8818
  var Duplex;
8819
8819
  Readable.ReadableState = ReadableState;
8820
- __webpack_require__("qU").EventEmitter;
8820
+ __webpack_require__("q").EventEmitter;
8821
8821
  var EElistenerCount = function(emitter, type) {
8822
8822
  return emitter.listeners(type).length;
8823
8823
  };
@@ -8836,7 +8836,7 @@
8836
8836
  var debug = void 0;
8837
8837
  debug = debugUtil && debugUtil.debuglog ? debugUtil.debuglog('stream') : function() {};
8838
8838
  var BufferList = __webpack_require__("aI");
8839
- var destroyImpl = __webpack_require__("R");
8839
+ var destroyImpl = __webpack_require__("R5");
8840
8840
  var StringDecoder;
8841
8841
  util.inherits(Readable, Stream);
8842
8842
  var kProxyEvents = [
@@ -9571,7 +9571,7 @@
9571
9571
  function _isUint8Array(obj) {
9572
9572
  return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;
9573
9573
  }
9574
- var destroyImpl = __webpack_require__("R");
9574
+ var destroyImpl = __webpack_require__("R5");
9575
9575
  util.inherits(Writable, Stream);
9576
9576
  function nop() {}
9577
9577
  function WritableState(options, stream) {
@@ -10025,7 +10025,7 @@
10025
10025
  return this.constructor.name + ' ' + obj;
10026
10026
  };
10027
10027
  },
10028
- R (module1, __unused_rspack_exports, __webpack_require__) {
10028
+ R5 (module1, __unused_rspack_exports, __webpack_require__) {
10029
10029
  "use strict";
10030
10030
  var pna = __webpack_require__("sj");
10031
10031
  function destroy(err, cb) {
@@ -10081,7 +10081,7 @@
10081
10081
  };
10082
10082
  },
10083
10083
  O (module1, __unused_rspack_exports, __webpack_require__) {
10084
- module1.exports = __webpack_require__("qU").EventEmitter;
10084
+ module1.exports = __webpack_require__("q").EventEmitter;
10085
10085
  },
10086
10086
  Fo (module1, exports1, __webpack_require__) {
10087
10087
  exports1 = module1.exports = __webpack_require__("w");
@@ -10571,7 +10571,7 @@
10571
10571
  a () {},
10572
10572
  Av () {},
10573
10573
  eD () {},
10574
- Ly (module1) {
10574
+ zm (module1) {
10575
10575
  "use strict";
10576
10576
  module1.exports = function(cssWithMappingToString) {
10577
10577
  var list = [];
@@ -10625,13 +10625,13 @@
10625
10625
  return list;
10626
10626
  };
10627
10627
  },
10628
- K7 (module1) {
10628
+ erX (module1) {
10629
10629
  "use strict";
10630
10630
  module1.exports = function(i) {
10631
10631
  return i[1];
10632
10632
  };
10633
10633
  },
10634
- q (module1) {
10634
+ R (module1) {
10635
10635
  "use strict";
10636
10636
  var stylesInDOM = [];
10637
10637
  function getIndexByIdentifier(identifier) {
@@ -10710,7 +10710,7 @@
10710
10710
  };
10711
10711
  };
10712
10712
  },
10713
- f (module1) {
10713
+ uZ (module1) {
10714
10714
  "use strict";
10715
10715
  var memo = {};
10716
10716
  function getTarget(target) {
@@ -10732,7 +10732,7 @@
10732
10732
  }
10733
10733
  module1.exports = insertBySelector;
10734
10734
  },
10735
- z7 (module1) {
10735
+ mK (module1) {
10736
10736
  "use strict";
10737
10737
  function insertStyleElement(options) {
10738
10738
  var element = document.createElement("style");
@@ -10742,7 +10742,7 @@
10742
10742
  }
10743
10743
  module1.exports = insertStyleElement;
10744
10744
  },
10745
- g (module1, __unused_rspack_exports, __webpack_require__) {
10745
+ kU (module1, __unused_rspack_exports, __webpack_require__) {
10746
10746
  "use strict";
10747
10747
  function setAttributesWithoutAttributes(styleElement) {
10748
10748
  var nonce = __webpack_require__.nc;
@@ -10750,7 +10750,7 @@
10750
10750
  }
10751
10751
  module1.exports = setAttributesWithoutAttributes;
10752
10752
  },
10753
- V (module1) {
10753
+ Bd (module1) {
10754
10754
  "use strict";
10755
10755
  function apply(styleElement, options, obj) {
10756
10756
  var css = "";
@@ -10787,7 +10787,7 @@
10787
10787
  }
10788
10788
  module1.exports = domAPI;
10789
10789
  },
10790
- AD (module1) {
10790
+ snK (module1) {
10791
10791
  "use strict";
10792
10792
  function styleTagTransform(css, styleElement) {
10793
10793
  if (styleElement.styleSheet) styleElement.styleSheet.cssText = css;
@@ -11132,7 +11132,7 @@
11132
11132
  var client = __webpack_require__("Q");
11133
11133
  var client_default = /*#__PURE__*/ __webpack_require__.n(client);
11134
11134
  var package_namespaceObject = {
11135
- rE: "16.4.1"
11135
+ rE: "16.5.0"
11136
11136
  };
11137
11137
  function isAudioEnabled(options) {
11138
11138
  return Boolean(options.audio.enabled);
@@ -14647,12 +14647,12 @@
14647
14647
  const errName = err?.name ?? err?.constructor.name;
14648
14648
  switch(errName){
14649
14649
  case error_VideomailError.SECURITY_ERROR:
14650
- message = "The operation was insecure";
14651
- explanation = "Probably you have disallowed Cookies for this page?";
14650
+ message = "Your browser blocked this action";
14651
+ explanation = "Check this page's camera permissions and security settings.";
14652
14652
  classList.push(error_VideomailError.BROWSER_PROBLEM);
14653
14653
  break;
14654
14654
  case error_VideomailError.OVERCONSTRAINED:
14655
- message = "Invalid webcam constraints";
14655
+ message = "Your webcam cannot use these settings";
14656
14656
  if (err && "constraint" in err) {
14657
14657
  const overconstrainedError = err;
14658
14658
  const constraint = overconstrainedError.constraint;
@@ -14663,64 +14663,64 @@
14663
14663
  break;
14664
14664
  case "MediaDeviceFailedDueToShutdown":
14665
14665
  message = "Webcam is shutting down";
14666
- explanation = "This happens your webcam is already switching off and not giving you permission to use it.";
14666
+ explanation = "Wait for your webcam to finish switching off, then try again.";
14667
14667
  break;
14668
14668
  case "SourceUnavailableError":
14669
- message = "Source of your webcam cannot be accessed";
14670
- explanation = "Probably it is locked from another process or has a hardware error.";
14669
+ message = "Cannot access your webcam";
14670
+ explanation = "Another app may be using it, or there may be a hardware problem.";
14671
14671
  break;
14672
14672
  case "NO_DEVICES_FOUND":
14673
14673
  if (audioEnabled) {
14674
- message = "No webcam nor microphone found";
14675
- explanation = "Your browser cannot find a webcam with microphone attached to your machine.";
14674
+ message = "No webcam or microphone found";
14675
+ explanation = "Check that your webcam and microphone are connected.";
14676
14676
  } else {
14677
14677
  message = "No webcam found";
14678
- explanation = "Your browser cannot find a webcam attached to your machine.";
14678
+ explanation = "Check that your webcam is connected.";
14679
14679
  }
14680
14680
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14681
14681
  break;
14682
14682
  case "PermissionDismissedError":
14683
- message = "Ooops, you didn't give me any permissions?";
14684
- explanation = "Looks like you skipped the webcam permission dialogue.<br/>Please grant access next time the dialogue appears.";
14683
+ message = "Camera permission is needed";
14684
+ explanation = "The camera permission prompt was closed.<br/>Please allow access when it appears again.";
14685
14685
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14686
14686
  break;
14687
14687
  case error_VideomailError.NOT_ALLOWED_ERROR:
14688
14688
  case error_VideomailError.PERMISSION_DENIED:
14689
14689
  case "PermissionDeniedError":
14690
14690
  message = "Permission denied";
14691
- 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.";
14691
+ 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>";
14692
14692
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14693
14693
  break;
14694
14694
  case "HARDWARE_UNAVAILABLE":
14695
14695
  case "AbortError":
14696
14696
  message = "Webcam is unavailable";
14697
- explanation = "Maybe it is already busy in another window?";
14697
+ explanation = "Another window may be using it. Close it and try again.";
14698
14698
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14699
14699
  break;
14700
14700
  case "NO_VIDEO_FEED":
14701
- message = "No video feed found!";
14702
- explanation = "Your webcam is already used in another browser.";
14701
+ message = "No video feed found";
14702
+ explanation = "Another browser may be using your webcam.";
14703
14703
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14704
14704
  break;
14705
14705
  case error_VideomailError.STARTING_FAILED:
14706
- message = "Starting video failed";
14707
- explanation = "Most likely this happens when the webcam is already active in another browser";
14706
+ message = "Could not start recording";
14707
+ explanation = "Another browser may be using your webcam.";
14708
14708
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14709
14709
  break;
14710
14710
  case "DevicesNotFoundError":
14711
- message = "No available webcam could be found";
14712
- explanation = "Looks like you do not have any webcam attached to your machine; or the one you plugged in is already used.";
14711
+ message = "No available webcam found";
14712
+ explanation = "Check that your webcam is connected and not being used by another app.";
14713
14713
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14714
14714
  break;
14715
14715
  case error_VideomailError.NOT_READABLE_ERROR:
14716
14716
  case error_VideomailError.TRACK_START_ERROR:
14717
- message = "No access to webcam";
14718
- explanation = "Perhaps you are already using it in another browser?";
14717
+ message = "Cannot access your webcam";
14718
+ explanation = "Another browser may be using it. Close it and try again.";
14719
14719
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14720
14720
  break;
14721
14721
  case error_VideomailError.INVALID_STATE_ERROR:
14722
- message = "Invalid state";
14723
- explanation = "Video recording stream from your webcam already has finished";
14722
+ message = "Your camera stream has ended";
14723
+ explanation = "The webcam stream is no longer active.";
14724
14724
  classList.push(error_VideomailError.WEBCAM_PROBLEM);
14725
14725
  break;
14726
14726
  case error_VideomailError.DOM_EXCEPTION:
@@ -15700,19 +15700,19 @@
15700
15700
  return newOptions;
15701
15701
  }
15702
15702
  const options_mergeWithDefaultOptions = mergeWithDefaultOptions;
15703
- var injectStylesIntoStyleTag = __webpack_require__("q");
15703
+ var injectStylesIntoStyleTag = __webpack_require__("R");
15704
15704
  var injectStylesIntoStyleTag_default = /*#__PURE__*/ __webpack_require__.n(injectStylesIntoStyleTag);
15705
- var styleDomAPI = __webpack_require__("V");
15705
+ var styleDomAPI = __webpack_require__("Bd");
15706
15706
  var styleDomAPI_default = /*#__PURE__*/ __webpack_require__.n(styleDomAPI);
15707
- var insertBySelector = __webpack_require__("f");
15707
+ var insertBySelector = __webpack_require__("uZ");
15708
15708
  var insertBySelector_default = /*#__PURE__*/ __webpack_require__.n(insertBySelector);
15709
- var setAttributesWithoutAttributes = __webpack_require__("g");
15709
+ var setAttributesWithoutAttributes = __webpack_require__("kU");
15710
15710
  var setAttributesWithoutAttributes_default = /*#__PURE__*/ __webpack_require__.n(setAttributesWithoutAttributes);
15711
- var insertStyleElement = __webpack_require__("z7");
15711
+ var insertStyleElement = __webpack_require__("mK");
15712
15712
  var insertStyleElement_default = /*#__PURE__*/ __webpack_require__.n(insertStyleElement);
15713
- var styleTagTransform = __webpack_require__("AD");
15713
+ var styleTagTransform = __webpack_require__("snK");
15714
15714
  var styleTagTransform_default = /*#__PURE__*/ __webpack_require__.n(styleTagTransform);
15715
- var main = __webpack_require__("pJ");
15715
+ var main = __webpack_require__("eq");
15716
15716
  var main_options = {};
15717
15717
  main_options.styleTagTransform = styleTagTransform_default();
15718
15718
  main_options.setAttributes = setAttributesWithoutAttributes_default();
@@ -20959,10 +20959,7 @@
20959
20959
  "droidcam"
20960
20960
  ];
20961
20961
  function isVirtualCamera(videoTrack) {
20962
- const capabilities = videoTrack.getCapabilities();
20963
- if (!capabilities.frameRate) return true;
20964
- const isVirtual = VIRTUAL_KEYWORDS.some((keyword)=>videoTrack.label.toLowerCase().includes(keyword));
20965
- return isVirtual;
20962
+ return VIRTUAL_KEYWORDS.some((keyword)=>videoTrack.label.toLowerCase().includes(keyword));
20966
20963
  }
20967
20964
  const util_isVirtualCamera = isVirtualCamera;
20968
20965
  const EVENT_ASCII = "|—O—|";
@@ -21357,7 +21354,7 @@
21357
21354
  let explanation = "(No explanation given)";
21358
21355
  if (command.args?.err?.message) explanation = command.args.err.message;
21359
21356
  const err = error_createError({
21360
- message: "Websocket error from Videomail server",
21357
+ message: "WebSocket error from the Videomail server",
21361
21358
  explanation,
21362
21359
  err: deserializeError(command.args?.err),
21363
21360
  options: this.options
@@ -22601,7 +22598,7 @@
22601
22598
  }
22602
22599
  async submit() {
22603
22600
  this.options.logger.debug("Container: submit()");
22604
- if (this.lastValidation) return await this.form?.doTheSubmit();
22601
+ if (!this.options.enableAutoValidation || this.lastValidation) return await this.form?.doTheSubmit();
22605
22602
  return false;
22606
22603
  }
22607
22604
  isCountingDown() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "videomail-client",
3
- "version": "16.4.1",
3
+ "version": "16.5.0",
4
4
  "description": "A wicked npm package to record videos directly in the browser, for Deaf and Sign Language!",
5
5
  "keywords": [
6
6
  "webcam",
@@ -88,7 +88,7 @@
88
88
  "@rsbuild/plugin-node-polyfill": "1.4.6",
89
89
  "@rsbuild/plugin-stylus": "2.0.1",
90
90
  "@rsdoctor/rspack-plugin": "1.6.5",
91
- "@rslib/core": "1.0.4",
91
+ "@rslib/core": "1.0.5",
92
92
  "@storybook/addon-a11y": "10.6.5",
93
93
  "@storybook/addon-docs": "10.6.5",
94
94
  "@storybook/addon-links": "10.6.5",
@@ -101,7 +101,7 @@
101
101
  "@types/ua-parser-js": "0.7.39",
102
102
  "@vitest/eslint-plugin": "1.6.28",
103
103
  "audit-ci": "7.1.0",
104
- "chromatic": "18.13.4",
104
+ "chromatic": "18.13.6",
105
105
  "cross-env": "10.1.0",
106
106
  "eslint": "10.13.0",
107
107
  "eslint-import-resolver-typescript": "4.4.5",