@es-joy/jsoe 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/.ncurc.cjs +4 -5
  2. package/CHANGES.md +4 -0
  3. package/README.md +27 -3
  4. package/badges/licenses-badge.svg +1 -0
  5. package/dist/formatAndTypeChoices.d.ts +39 -19
  6. package/dist/formatAndTypeChoices.d.ts.map +1 -1
  7. package/dist/formats/indexedDBKey.d.ts +1 -1
  8. package/dist/formats/indexedDBKey.d.ts.map +1 -1
  9. package/dist/formats/json.d.ts +1 -1
  10. package/dist/formats/json.d.ts.map +1 -1
  11. package/dist/formats/schema.d.ts +11 -0
  12. package/dist/formats/schema.d.ts.map +1 -0
  13. package/dist/formats/structuredCloning.d.ts +11 -13
  14. package/dist/formats/structuredCloning.d.ts.map +1 -1
  15. package/dist/formats.d.ts +86 -25
  16. package/dist/formats.d.ts.map +1 -1
  17. package/dist/fundamentalTypes/BooleanObjectType.d.ts +1 -1
  18. package/dist/fundamentalTypes/BooleanObjectType.d.ts.map +1 -1
  19. package/dist/fundamentalTypes/NumberObjectType.d.ts +1 -1
  20. package/dist/fundamentalTypes/NumberObjectType.d.ts.map +1 -1
  21. package/dist/fundamentalTypes/StringObjectType.d.ts +1 -1
  22. package/dist/fundamentalTypes/StringObjectType.d.ts.map +1 -1
  23. package/dist/fundamentalTypes/arrayReferenceType.d.ts +1 -1
  24. package/dist/fundamentalTypes/arrayType.d.ts +3 -3
  25. package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
  26. package/dist/fundamentalTypes/bigintObjectType.d.ts +6 -0
  27. package/dist/fundamentalTypes/bigintObjectType.d.ts.map +1 -0
  28. package/dist/fundamentalTypes/bigintType.d.ts +1 -1
  29. package/dist/fundamentalTypes/bigintType.d.ts.map +1 -1
  30. package/dist/fundamentalTypes/blobType.d.ts +1 -1
  31. package/dist/fundamentalTypes/blobType.d.ts.map +1 -1
  32. package/dist/fundamentalTypes/booleanType.d.ts +8 -0
  33. package/dist/fundamentalTypes/booleanType.d.ts.map +1 -0
  34. package/dist/fundamentalTypes/catchType.d.ts +6 -0
  35. package/dist/fundamentalTypes/catchType.d.ts.map +1 -0
  36. package/dist/fundamentalTypes/dateType.d.ts +4 -4
  37. package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
  38. package/dist/fundamentalTypes/domexceptionType.d.ts +1 -1
  39. package/dist/fundamentalTypes/domexceptionType.d.ts.map +1 -1
  40. package/dist/fundamentalTypes/enumType.d.ts +6 -0
  41. package/dist/fundamentalTypes/enumType.d.ts.map +1 -0
  42. package/dist/fundamentalTypes/errorType.d.ts +1 -1
  43. package/dist/fundamentalTypes/errorType.d.ts.map +1 -1
  44. package/dist/fundamentalTypes/fileType.d.ts +1 -1
  45. package/dist/fundamentalTypes/fileType.d.ts.map +1 -1
  46. package/dist/fundamentalTypes/filelistType.d.ts +1 -1
  47. package/dist/fundamentalTypes/filelistType.d.ts.map +1 -1
  48. package/dist/fundamentalTypes/functionType.d.ts +6 -0
  49. package/dist/fundamentalTypes/functionType.d.ts.map +1 -0
  50. package/dist/fundamentalTypes/literalType.d.ts +6 -0
  51. package/dist/fundamentalTypes/literalType.d.ts.map +1 -0
  52. package/dist/fundamentalTypes/mapType.d.ts +1 -1
  53. package/dist/fundamentalTypes/mapType.d.ts.map +1 -1
  54. package/dist/fundamentalTypes/nanType.d.ts +6 -0
  55. package/dist/fundamentalTypes/nanType.d.ts.map +1 -0
  56. package/dist/fundamentalTypes/nativeEnumType.d.ts +6 -0
  57. package/dist/fundamentalTypes/nativeEnumType.d.ts.map +1 -0
  58. package/dist/fundamentalTypes/neverType.d.ts +6 -0
  59. package/dist/fundamentalTypes/neverType.d.ts.map +1 -0
  60. package/dist/fundamentalTypes/noneditableType.d.ts +1 -1
  61. package/dist/fundamentalTypes/noneditableType.d.ts.map +1 -1
  62. package/dist/fundamentalTypes/nullType.d.ts +1 -1
  63. package/dist/fundamentalTypes/nullType.d.ts.map +1 -1
  64. package/dist/fundamentalTypes/numberType.d.ts +1 -1
  65. package/dist/fundamentalTypes/numberType.d.ts.map +1 -1
  66. package/dist/fundamentalTypes/objectReferenceType.d.ts +1 -1
  67. package/dist/fundamentalTypes/objectType.d.ts +1 -1
  68. package/dist/fundamentalTypes/objectType.d.ts.map +1 -1
  69. package/dist/fundamentalTypes/promiseType.d.ts +6 -0
  70. package/dist/fundamentalTypes/promiseType.d.ts.map +1 -0
  71. package/dist/fundamentalTypes/recordType.d.ts +6 -0
  72. package/dist/fundamentalTypes/recordType.d.ts.map +1 -0
  73. package/dist/fundamentalTypes/regexpType.d.ts +1 -1
  74. package/dist/fundamentalTypes/regexpType.d.ts.map +1 -1
  75. package/dist/fundamentalTypes/setType.d.ts +1 -1
  76. package/dist/fundamentalTypes/setType.d.ts.map +1 -1
  77. package/dist/fundamentalTypes/sparseUndefinedType.d.ts +1 -1
  78. package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -1
  79. package/dist/fundamentalTypes/stringType.d.ts +1 -1
  80. package/dist/fundamentalTypes/stringType.d.ts.map +1 -1
  81. package/dist/fundamentalTypes/symbolType.d.ts +8 -0
  82. package/dist/fundamentalTypes/symbolType.d.ts.map +1 -0
  83. package/dist/fundamentalTypes/tupleType.d.ts +6 -0
  84. package/dist/fundamentalTypes/tupleType.d.ts.map +1 -0
  85. package/dist/fundamentalTypes/undefinedType.d.ts +1 -1
  86. package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -1
  87. package/dist/fundamentalTypes/voidType.d.ts +6 -0
  88. package/dist/fundamentalTypes/voidType.d.ts.map +1 -0
  89. package/dist/index.d.ts +2 -2
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +9660 -1586
  92. package/dist/subTypes/blobHTMLType.d.ts.map +1 -1
  93. package/dist/subTypes/falseType.d.ts +1 -1
  94. package/dist/subTypes/trueType.d.ts +1 -1
  95. package/dist/superTypes/SpecialNumberType.d.ts +1 -1
  96. package/dist/superTypes/SpecialRealNumberType.d.ts +1 -1
  97. package/dist/superTypes/SpecialRealNumberType.d.ts.map +1 -1
  98. package/dist/superTypes/buffersourceType.d.ts +1 -1
  99. package/dist/superTypes/buffersourceType.d.ts.map +1 -1
  100. package/dist/superTypes/dommatrixType.d.ts +1 -1
  101. package/dist/superTypes/dommatrixType.d.ts.map +1 -1
  102. package/dist/superTypes/dompointType.d.ts +1 -1
  103. package/dist/superTypes/dompointType.d.ts.map +1 -1
  104. package/dist/superTypes/domrectType.d.ts +1 -1
  105. package/dist/superTypes/domrectType.d.ts.map +1 -1
  106. package/dist/superTypes/errorsSpecialType.d.ts +1 -1
  107. package/dist/superTypes/errorsSpecialType.d.ts.map +1 -1
  108. package/dist/typeChoices.d.ts +33 -16
  109. package/dist/typeChoices.d.ts.map +1 -1
  110. package/dist/types.d.ts +161 -157
  111. package/dist/types.d.ts.map +1 -1
  112. package/dist/utils/dialogs.d.ts +3 -3
  113. package/dist/utils/dialogs.d.ts.map +1 -1
  114. package/dist/utils/jsonPointer.d.ts.map +1 -1
  115. package/dist/utils/media.d.ts.map +1 -1
  116. package/dist/utils/objects.d.ts +16 -0
  117. package/dist/utils/objects.d.ts.map +1 -0
  118. package/dist/utils/types.d.ts +1 -1
  119. package/dist/utils/types.d.ts.map +1 -1
  120. package/dist/vendor-imports.d.ts +1 -1
  121. package/eslint.config.js +74 -0
  122. package/licenseInfo.json +4 -0
  123. package/package.json +33 -42
  124. package/rollup.config.js +15 -0
  125. package/src/formatAndTypeChoices.js +68 -54
  126. package/src/formats/indexedDBKey.js +9 -4
  127. package/src/formats/json.js +7 -4
  128. package/src/formats/schema.js +772 -0
  129. package/src/formats/structuredCloning.js +187 -86
  130. package/src/formats.js +61 -26
  131. package/src/fundamentalTypes/BooleanObjectType.js +18 -6
  132. package/src/fundamentalTypes/NumberObjectType.js +18 -5
  133. package/src/fundamentalTypes/StringObjectType.js +20 -8
  134. package/src/fundamentalTypes/arrayType.js +1241 -533
  135. package/src/fundamentalTypes/bigintObjectType.js +64 -0
  136. package/src/fundamentalTypes/bigintType.js +31 -5
  137. package/src/fundamentalTypes/blobType.js +201 -190
  138. package/src/fundamentalTypes/booleanType.js +63 -0
  139. package/src/fundamentalTypes/catchType.js +140 -0
  140. package/src/fundamentalTypes/dateType.js +57 -19
  141. package/src/fundamentalTypes/domexceptionType.js +61 -63
  142. package/src/fundamentalTypes/enumType.js +52 -0
  143. package/src/fundamentalTypes/errorType.js +20 -7
  144. package/src/fundamentalTypes/fileType.js +195 -189
  145. package/src/fundamentalTypes/filelistType.js +4 -0
  146. package/src/fundamentalTypes/functionType.js +150 -0
  147. package/src/fundamentalTypes/literalType.js +81 -0
  148. package/src/fundamentalTypes/mapType.js +4 -0
  149. package/src/fundamentalTypes/nanType.js +41 -0
  150. package/src/fundamentalTypes/nativeEnumType.js +155 -0
  151. package/src/fundamentalTypes/neverType.js +44 -0
  152. package/src/fundamentalTypes/noneditableType.js +19 -5
  153. package/src/fundamentalTypes/nullType.js +16 -6
  154. package/src/fundamentalTypes/numberType.js +49 -6
  155. package/src/fundamentalTypes/objectType.js +10 -2
  156. package/src/fundamentalTypes/promiseType.js +60 -0
  157. package/src/fundamentalTypes/recordType.js +42 -0
  158. package/src/fundamentalTypes/regexpType.js +51 -33
  159. package/src/fundamentalTypes/setType.js +4 -0
  160. package/src/fundamentalTypes/sparseUndefinedType.js +3 -0
  161. package/src/fundamentalTypes/stringType.js +254 -6
  162. package/src/fundamentalTypes/symbolType.js +81 -0
  163. package/src/fundamentalTypes/tupleType.js +39 -0
  164. package/src/fundamentalTypes/undefinedType.js +14 -4
  165. package/src/fundamentalTypes/voidType.js +48 -0
  166. package/src/jsoe.css +37 -3
  167. package/src/subTypes/blobHTMLType.js +33 -24
  168. package/src/superTypes/SpecialRealNumberType.js +22 -6
  169. package/src/superTypes/buffersourceType.js +86 -30
  170. package/src/superTypes/dommatrixType.js +24 -7
  171. package/src/superTypes/dompointType.js +27 -7
  172. package/src/superTypes/domrectType.js +33 -7
  173. package/src/superTypes/errorsSpecialType.js +30 -14
  174. package/src/typeChoices.js +115 -44
  175. package/src/types.js +129 -45
  176. package/src/utils/FileList.js +3 -3
  177. package/src/utils/dialogs.js +6 -8
  178. package/src/utils/objects.js +22 -0
  179. package/src/vendor-imports.js +1 -1
  180. package/tsconfig.json +2 -2
  181. package/vendor/jamilih/dist/jml-es.js +23 -6
  182. package/vendor/typeson-registry/dist/index.js +77 -47
  183. package/vendor/zod/lib/index.mjs +4236 -0
  184. package/vendor/zodex/dist/esm/dezerialize.d.ts +26 -0
  185. package/vendor/zodex/dist/esm/dezerialize.js +393 -0
  186. package/vendor/zodex/dist/esm/index.d.ts +9 -0
  187. package/vendor/zodex/dist/esm/index.js +4 -0
  188. package/vendor/zodex/dist/esm/infer.d.ts +29 -0
  189. package/vendor/zodex/dist/esm/infer.js +1 -0
  190. package/vendor/zodex/dist/esm/package.json +1 -0
  191. package/vendor/zodex/dist/esm/types.d.ts +201 -0
  192. package/vendor/zodex/dist/esm/types.js +13 -0
  193. package/vendor/zodex/dist/esm/ui.d.ts +23 -0
  194. package/vendor/zodex/dist/esm/ui.js +10 -0
  195. package/vendor/zodex/dist/esm/zerialize.d.ts +50 -0
  196. package/vendor/zodex/dist/esm/zerialize.js +417 -0
  197. package/vendor/zodex/dist/esm/zod-types.d.ts +11 -0
  198. package/vendor/zodex/dist/esm/zod-types.js +1 -0
  199. package/.eslintignore +0 -13
  200. package/.eslintrc.cjs +0 -145
  201. package/.nyc_output/out.json +0 -117370
  202. package/cypress.config.ts +0 -15
  203. package/demo/index-instrumented.html +0 -29
  204. package/demo/index-instrumented.js +0 -644
  205. package/demo/index.html +0 -29
  206. package/demo/index.js +0 -215
  207. package/src/formats/schemaAndArbitrary.js +0 -20
  208. package/src/formats/schemaOnly.js +0 -539
@@ -0,0 +1,64 @@
1
+ import {hasConstructorOf} from '../vendor-imports.js';
2
+ import {$e} from '../utils/templateUtils.js';
3
+
4
+ /**
5
+ * @type {import('../types.js').TypeObject}
6
+ */
7
+ const bigintObjectType = {
8
+ option: ['BigInt Object'],
9
+ stringRegex: new RegExp(
10
+ '^BigIntObject' +
11
+ '-?' + // Optional negative sign.
12
+ // How many digits?
13
+ '[0-9]{1,}' +
14
+ 'n' +
15
+ '$', // No trailing content.
16
+ 'u'
17
+ ),
18
+ valueMatch (x) {
19
+ return typeof x === 'object' && hasConstructorOf(x, BigInt);
20
+ },
21
+ toValue (s) {
22
+ return {value: new Object(BigInt(s.slice(12, -1)))};
23
+ },
24
+ getInput ({root}) {
25
+ return /** @type {HTMLInputElement} */ ($e(root, 'input'));
26
+ },
27
+ setValue ({root, value}) {
28
+ this.getInput({root}).value = String(value);
29
+ },
30
+ validate ({root}) {
31
+ const val = this.getInput({root}).value;
32
+ return {
33
+ message: 'Not a valid BigInt',
34
+ valid: Boolean(val && (/^-?(\d+)$/u).test(val))
35
+ };
36
+ },
37
+ getValue ({root}) {
38
+ return new Object(BigInt(this.getInput({root}).value));
39
+ },
40
+ /* schema:
41
+ viewSchemaUI () {
42
+ // Todo?
43
+ },
44
+ */
45
+ viewUI ({value, specificSchemaObject}) {
46
+ return ['i', {
47
+ dataset: {type: 'bigintObject'},
48
+ title: specificSchemaObject?.description ?? '(a BigInt Object)'
49
+ }, [`${String(value)}n`]];
50
+ },
51
+ editUI ({typeNamespace, specificSchemaObject, value = ''}) {
52
+ return ['div', {
53
+ dataset: {type: 'bigintObject'},
54
+ title: specificSchemaObject?.description ?? 'BigInt object'
55
+ }, [
56
+ ['input', {
57
+ name: `${typeNamespace}-bigintObject`, type: 'number', step: '1',
58
+ value
59
+ }]
60
+ ]];
61
+ }
62
+ };
63
+
64
+ export default bigintObjectType;
@@ -14,6 +14,9 @@ const bigintType = {
14
14
  '$', // No trailing content.
15
15
  'u'
16
16
  ),
17
+ valueMatch (x) {
18
+ return typeof x === 'bigint';
19
+ },
17
20
  toValue (s) {
18
21
  return {value: BigInt(s.slice(0, -1))};
19
22
  },
@@ -38,13 +41,36 @@ const bigintType = {
38
41
  // Todo?
39
42
  },
40
43
  */
41
- viewUI ({value}) {
42
- return ['i', {dataset: {type: 'bigint'}}, [`${String(value)}n`]];
44
+ viewUI ({value, specificSchemaObject}) {
45
+ return ['i', {
46
+ dataset: {type: 'bigint'},
47
+ title: specificSchemaObject?.description ?? '(a BigInt)'
48
+ }, [
49
+ `${String(value)}n`
50
+ ]];
43
51
  },
44
- editUI ({typeNamespace, value = ''}) {
45
- return ['div', {dataset: {type: 'bigint'}}, [
52
+ editUI ({typeNamespace, specificSchemaObject, value}) {
53
+ const bigintSchemaObject = /** @type {import('zodex').SzBigInt} */ (
54
+ specificSchemaObject
55
+ );
56
+ return ['div', {
57
+ dataset: {type: 'bigint'},
58
+ title: specificSchemaObject?.description ?? 'BigInt'
59
+ }, [
46
60
  ['input', {
47
- name: `${typeNamespace}-bigint`, type: 'number', step: 'any', value
61
+ name: `${typeNamespace}-bigint`, type: 'number',
62
+ value: value ?? specificSchemaObject?.defaultValue ?? '',
63
+ min: bigintSchemaObject?.min
64
+ ? bigintSchemaObject?.minInclusive
65
+ ? bigintSchemaObject?.min
66
+ : String(BigInt(bigintSchemaObject?.min) + 1n)
67
+ : undefined,
68
+ max: bigintSchemaObject?.max
69
+ ? bigintSchemaObject?.maxInclusive
70
+ ? bigintSchemaObject?.max
71
+ : String(BigInt(bigintSchemaObject?.max) - 1n)
72
+ : undefined,
73
+ step: bigintSchemaObject?.multipleOf ?? '1'
48
74
  }]
49
75
  ]];
50
76
  }
@@ -1,4 +1,4 @@
1
- import {jml} from '../vendor-imports.js';
1
+ import {jml, toStringTag} from '../vendor-imports.js';
2
2
  import {$e} from '../utils/templateUtils.js';
3
3
  import {visualize, getUserMedia, startScreenCapture} from '../utils/media.js';
4
4
  import dialogs from '../utils/dialogs.js';
@@ -20,7 +20,7 @@ import dialogs from '../utils/dialogs.js';
20
20
  * name?: string,
21
21
  * type?: string
22
22
  * }} value
23
- * @returns {void}
23
+ * @returns {Blob}
24
24
  */
25
25
  function newBlobForBinary (viewBinary, value) {
26
26
  const oldBlob = /** @type {Blob|undefined} */ (
@@ -52,6 +52,7 @@ function newBlobForBinary (viewBinary, value) {
52
52
  }
53
53
  );
54
54
  viewBinary.$value = blob;
55
+ return blob;
55
56
  }
56
57
 
57
58
  /**
@@ -97,9 +98,12 @@ function binaryButton (value, editable) {
97
98
  const textarea = /** @type {HTMLTextAreaElement} */ (
98
99
  $e(dialog, '.view-binary')
99
100
  );
100
- newBlobForBinary(viewBinary, {
101
+ const blob = newBlobForBinary(viewBinary, {
101
102
  stringContents: textarea.value
102
103
  });
104
+ // May need to update size:
105
+ /** @type {HTMLFieldSetElement & {$setValue: SetValue}} */
106
+ (viewBinary.parentElement).$setValue(blob);
103
107
  dialog.close();
104
108
  },
105
109
  // @ts-expect-error TS bug
@@ -146,6 +150,9 @@ function binaryButton (value, editable) {
146
150
  const blobType = {
147
151
  option: ['Blob'],
148
152
  stringRegex: /^Blob\((.*)\)$/u,
153
+ valueMatch (x) {
154
+ return toStringTag(x) === 'Blob';
155
+ },
149
156
  toValue (s) {
150
157
  const obj = JSON.parse(s);
151
158
  return {value: new Blob([obj.stringContents], {
@@ -166,10 +173,13 @@ const blobType = {
166
173
  this.getInput({root})
167
174
  ).$value;
168
175
  },
169
- viewUI ({value}) {
176
+ viewUI ({value, specificSchemaObject}) {
170
177
  return ['div', {dataset: {type: 'blob'}}, [
171
- ['b', {class: 'emphasis'}, [
172
- 'Blob'
178
+ ['b', {
179
+ class: 'emphasis',
180
+ title: specificSchemaObject?.description ? '(a Blob)' : undefined
181
+ }, [
182
+ specificSchemaObject?.description ?? 'Blob'
173
183
  ]],
174
184
  ['br'],
175
185
  ['br'],
@@ -185,7 +195,7 @@ const blobType = {
185
195
  ['br'],
186
196
  value.type.startsWith('text/') || value.type === 'application/json'
187
197
  ? (() => {
188
- const div = /** @type {HTMLDivElement} */ (jml('div'));
198
+ const div = jml('div');
189
199
  const reader = new FileReader();
190
200
  reader.addEventListener('load', function () {
191
201
  div.append(jml('div', [
@@ -217,7 +227,7 @@ const blobType = {
217
227
  value.type.startsWith('video/')
218
228
  ? (() => {
219
229
  const objURL = URL.createObjectURL(value);
220
- const video = /** @type {HTMLVideoElement} */ (jml('video', {
230
+ const video = jml('video', {
221
231
  src: objURL,
222
232
  class: 'video',
223
233
  $on: {
@@ -225,7 +235,7 @@ const blobType = {
225
235
  URL.revokeObjectURL(objURL);
226
236
  }
227
237
  }
228
- }));
238
+ });
229
239
 
230
240
  return ['div', [
231
241
  video,
@@ -270,7 +280,7 @@ const blobType = {
270
280
  value.type.startsWith('audio/')
271
281
  ? (() => {
272
282
  const objURL = URL.createObjectURL(value);
273
- const audio = /** @type {HTMLAudioElement} */ (jml('audio', {
283
+ const audio = jml('audio', {
274
284
  src: objURL,
275
285
  class: 'audio',
276
286
  $on: {
@@ -278,7 +288,7 @@ const blobType = {
278
288
  URL.revokeObjectURL(objURL);
279
289
  }
280
290
  }
281
- }));
291
+ });
282
292
  return ['div', [
283
293
  audio,
284
294
  ['button', {
@@ -349,10 +359,13 @@ const blobType = {
349
359
  : ''
350
360
  ]];
351
361
  },
352
- editUI ({typeNamespace, value = {}}) {
362
+ editUI ({typeNamespace, specificSchemaObject, value = {}}) {
353
363
  // Todo: Could add way to preview blob in edit mode (whether
354
364
  // recorded or uploaded)
355
- return ['div', {dataset: {type: 'blob'}}, [
365
+ return ['div', {
366
+ dataset: {type: 'blob'},
367
+ title: specificSchemaObject?.description ?? 'Blob'
368
+ }, [
356
369
  ['fieldset', {
357
370
  class: 'blobMetaData',
358
371
  $custom: {
@@ -390,7 +403,7 @@ const blobType = {
390
403
  ['label', [
391
404
  'Size (in bytes) ',
392
405
  ['input', {
393
- type: 'number', disabled: true, class: 'size',
406
+ type: 'number', step: '1', disabled: true, class: 'size',
394
407
  value: String(value.size)
395
408
  }]
396
409
  ]],
@@ -481,194 +494,192 @@ const blobType = {
481
494
  'Supply blob through recording'
482
495
  ]],
483
496
  (() => {
484
- const select = /** @type {HTMLSelectElement} */ (
485
- jml('select', {
486
- class: 'device',
487
- $on: {
488
- async change () {
489
- const videoContainer = /** @type {HTMLDivElement} */ (
490
- this.nextElementSibling?.nextElementSibling
491
- );
497
+ const select = jml('select', {
498
+ class: 'device',
499
+ $on: {
500
+ async change () {
501
+ const videoContainer = /** @type {HTMLDivElement} */ (
502
+ this.nextElementSibling?.nextElementSibling
503
+ );
492
504
 
493
- const photo =
494
- /**
495
- * @type {HTMLCanvasElement}
496
- */
497
- ($e(videoContainer, 'img.photo'));
498
- photo.hidden = true;
499
-
500
- const oldVideo =
501
- /**
502
- * @type {HTMLVideoElement & {
503
- * $stream: MediaStream
504
- * }}
505
- */
506
- ($e(
507
- videoContainer,
508
- 'video.previewMedia'
509
- ));
510
-
511
- // Drop preexisting listeners
512
- const previewMedia =
513
- /**
514
- * @type {HTMLVideoElement & {
515
- * $stream: MediaStream,
516
- * $screenShare: boolean
517
- * }}
518
- */ (
519
- jml('video', {
520
- class: 'previewMedia'
521
- })
522
- );
523
-
524
- if (oldVideo.$stream) {
525
- const tracks = /** @type {MediaStream} */ (
526
- oldVideo.$stream
527
- ).getTracks();
528
- tracks.forEach((track) => {
529
- track.stop();
530
- });
531
- oldVideo.srcObject = null;
532
- }
505
+ const photo =
506
+ /**
507
+ * @type {HTMLCanvasElement}
508
+ */
509
+ ($e(videoContainer, 'img.photo'));
510
+ photo.hidden = true;
533
511
 
534
- oldVideo.replaceWith(previewMedia);
512
+ const oldVideo =
513
+ /**
514
+ * @type {HTMLVideoElement & {
515
+ * $stream: MediaStream
516
+ * }}
517
+ */
518
+ ($e(
519
+ videoContainer,
520
+ 'video.previewMedia'
521
+ ));
535
522
 
536
- const takeSnapshot = /** @type {HTMLButtonElement} */ (
537
- $e(/** @type {HTMLDivElement} */ (
538
- select.nextElementSibling
539
- ), '.takeSnapshot')
523
+ // Drop preexisting listeners
524
+ const previewMedia =
525
+ /**
526
+ * @type {HTMLVideoElement & {
527
+ * $stream: MediaStream,
528
+ * $screenShare: boolean
529
+ * }}
530
+ */ (
531
+ jml('video', {
532
+ class: 'previewMedia'
533
+ })
540
534
  );
541
535
 
542
- const recordMedia = /** @type {HTMLButtonElement} */ (
543
- $e(/** @type {HTMLDivElement} */ (
544
- select.nextElementSibling
545
- ), '.recordMedia')
546
- );
536
+ if (oldVideo.$stream) {
537
+ const tracks = /** @type {MediaStream} */ (
538
+ oldVideo.$stream
539
+ ).getTracks();
540
+ tracks.forEach((track) => {
541
+ track.stop();
542
+ });
543
+ oldVideo.srcObject = null;
544
+ }
547
545
 
548
- /** @type {HTMLDivElement} */ ($e(
549
- /** @type {HTMLDivElement} */
550
- (select.nextElementSibling?.
551
- nextElementSibling),
552
- 'div.recordedMedia'
553
- )).hidden = true;
546
+ oldVideo.replaceWith(previewMedia);
554
547
 
555
- const visualizer = /** @type {HTMLCanvasElement} */ (
556
- $e(videoContainer, 'canvas.visualizer')
557
- );
548
+ const takeSnapshot = /** @type {HTMLButtonElement} */ (
549
+ $e(/** @type {HTMLDivElement} */ (
550
+ select.nextElementSibling
551
+ ), '.takeSnapshot')
552
+ );
558
553
 
559
- /**
560
- * @type {{
561
- * video?: true,
562
- * audio?: true
563
- * }|undefined}
564
- */
565
- let constraints;
566
- let screenShareConstraints;
567
-
568
- previewMedia.$screenShare = false;
569
- switch (select.value) {
570
- case 'audio-and-video':
571
- constraints = {video: true, audio: true};
572
- previewMedia.hidden = false;
573
- takeSnapshot.hidden = false;
574
- recordMedia.textContent = 'Record video/audio';
575
- break;
576
- case 'video':
577
- constraints = {video: true};
578
- previewMedia.hidden = false;
579
- takeSnapshot.hidden = false;
580
- recordMedia.textContent = 'Record video';
581
- break;
582
- case 'audio':
583
- constraints = {audio: true};
584
- previewMedia.hidden = true;
585
- takeSnapshot.hidden = true;
586
- recordMedia.textContent = 'Record audio';
587
- break;
588
- case 'screenShare':
589
- screenShareConstraints = {video: true};
590
- // Fallthrough
591
- case 'screenShareAndVideo':
592
- if (!screenShareConstraints) {
593
- screenShareConstraints = {video: true, audio: true};
594
- }
595
- previewMedia.$screenShare = true;
596
- previewMedia.hidden = true;
597
- takeSnapshot.hidden = true;
598
- visualizer.hidden = true;
599
- break;
600
- default:
601
- return;
602
- }
554
+ const recordMedia = /** @type {HTMLButtonElement} */ (
555
+ $e(/** @type {HTMLDivElement} */ (
556
+ select.nextElementSibling
557
+ ), '.recordMedia')
558
+ );
603
559
 
604
- if (constraints) {
605
- const mediaStream = await getUserMedia(constraints);
606
- /* istanbul ignore if */
607
- if (!mediaStream) {
608
- await dialogs.alert('Error getting user media');
609
- return;
610
- }
560
+ /** @type {HTMLDivElement} */ ($e(
561
+ /** @type {HTMLDivElement} */
562
+ (select.nextElementSibling?.
563
+ nextElementSibling),
564
+ 'div.recordedMedia'
565
+ )).hidden = true;
611
566
 
612
- videoContainer.hidden = false;
613
- previewMedia.srcObject = mediaStream;
614
-
615
- // Save as stream for later reuse as stream
616
- previewMedia.$stream = mediaStream;
617
-
618
- if (constraints.video) {
619
- const canvas =
620
- /**
621
- * @type {HTMLCanvasElement}
622
- */
623
- ($e(
624
- videoContainer,
625
- 'canvas.recordedImage'
626
- ));
627
- // https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Taking_still_photos
628
- previewMedia.addEventListener('canplay', () => {
629
- canvas.setAttribute('width', String(
630
- previewMedia.videoWidth
631
- ));
632
- canvas.setAttribute(
633
- 'height', String(previewMedia.videoHeight)
634
- );
635
- });
636
- }
567
+ const visualizer = /** @type {HTMLCanvasElement} */ (
568
+ $e(videoContainer, 'canvas.visualizer')
569
+ );
637
570
 
638
- previewMedia.addEventListener('loadedmetadata', () => {
639
- previewMedia.play();
640
- if (constraints?.audio) {
641
- visualizer.hidden = false;
642
- visualize(
643
- mediaStream,
644
- visualizer
645
- );
646
- } else {
647
- visualizer.hidden = true;
648
- }
571
+ /**
572
+ * @type {{
573
+ * video?: true,
574
+ * audio?: true
575
+ * }|undefined}
576
+ */
577
+ let constraints;
578
+ let screenShareConstraints;
579
+
580
+ previewMedia.$screenShare = false;
581
+ switch (select.value) {
582
+ case 'audio-and-video':
583
+ constraints = {video: true, audio: true};
584
+ previewMedia.hidden = false;
585
+ takeSnapshot.hidden = false;
586
+ recordMedia.textContent = 'Record video/audio';
587
+ break;
588
+ case 'video':
589
+ constraints = {video: true};
590
+ previewMedia.hidden = false;
591
+ takeSnapshot.hidden = false;
592
+ recordMedia.textContent = 'Record video';
593
+ break;
594
+ case 'audio':
595
+ constraints = {audio: true};
596
+ previewMedia.hidden = true;
597
+ takeSnapshot.hidden = true;
598
+ recordMedia.textContent = 'Record audio';
599
+ break;
600
+ case 'screenShare':
601
+ screenShareConstraints = {video: true};
602
+ // Fallthrough
603
+ case 'screenShareAndVideo':
604
+ if (!screenShareConstraints) {
605
+ screenShareConstraints = {video: true, audio: true};
606
+ }
607
+ previewMedia.$screenShare = true;
608
+ previewMedia.hidden = true;
609
+ takeSnapshot.hidden = true;
610
+ visualizer.hidden = true;
611
+ break;
612
+ default:
613
+ return;
614
+ }
615
+
616
+ if (constraints) {
617
+ const mediaStream = await getUserMedia(constraints);
618
+ /* istanbul ignore if */
619
+ if (!mediaStream) {
620
+ await dialogs.alert('Error getting user media');
621
+ return;
622
+ }
623
+
624
+ videoContainer.hidden = false;
625
+ previewMedia.srcObject = mediaStream;
626
+
627
+ // Save as stream for later reuse as stream
628
+ previewMedia.$stream = mediaStream;
629
+
630
+ if (constraints.video) {
631
+ const canvas =
632
+ /**
633
+ * @type {HTMLCanvasElement}
634
+ */
635
+ ($e(
636
+ videoContainer,
637
+ 'canvas.recordedImage'
638
+ ));
639
+ // https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Taking_still_photos
640
+ previewMedia.addEventListener('canplay', () => {
641
+ canvas.setAttribute('width', String(
642
+ previewMedia.videoWidth
643
+ ));
644
+ canvas.setAttribute(
645
+ 'height', String(previewMedia.videoHeight)
646
+ );
649
647
  });
650
- } else if (screenShareConstraints) {
651
- const mediaStream = await startScreenCapture(
652
- screenShareConstraints
653
- );
654
- /* istanbul ignore if */
655
- if (!mediaStream) {
656
- await dialogs.alert('Error getting user media');
657
- return;
648
+ }
649
+
650
+ previewMedia.addEventListener('loadedmetadata', () => {
651
+ previewMedia.play();
652
+ if (constraints?.audio) {
653
+ visualizer.hidden = false;
654
+ visualize(
655
+ mediaStream,
656
+ visualizer
657
+ );
658
+ } else {
659
+ visualizer.hidden = true;
658
660
  }
661
+ });
662
+ } else if (screenShareConstraints) {
663
+ const mediaStream = await startScreenCapture(
664
+ screenShareConstraints
665
+ );
666
+ /* istanbul ignore if */
667
+ if (!mediaStream) {
668
+ await dialogs.alert('Error getting user media');
669
+ return;
670
+ }
659
671
 
660
- videoContainer.hidden = false;
661
- previewMedia.srcObject = mediaStream;
672
+ videoContainer.hidden = false;
673
+ previewMedia.srcObject = mediaStream;
662
674
 
663
- // Save as stream for later reuse as stream
664
- previewMedia.$stream = mediaStream;
665
- }
675
+ // Save as stream for later reuse as stream
676
+ previewMedia.$stream = mediaStream;
666
677
  }
667
678
  }
668
- }, [
669
- ['option', {value: ''}, ['Please choose a device']]
670
- ])
671
- );
679
+ }
680
+ }, [
681
+ ['option', {value: ''}, ['Please choose a device']]
682
+ ]);
672
683
 
673
684
  (async () => {
674
685
  const devices = await navigator.mediaDevices.enumerateDevices();
@@ -770,7 +781,7 @@ const blobType = {
770
781
  try {
771
782
  mediaRecorder.start();
772
783
  /* istanbul ignore next */
773
- } catch (err) {
784
+ } catch {
774
785
  /* istanbul ignore next */
775
786
  dialogs.alert('Error starting media recorder');
776
787
  /* istanbul ignore next */
@@ -909,9 +920,9 @@ const blobType = {
909
920
  dialogs.alert('Error converting canvas to Blob');
910
921
  return;
911
922
  }
912
- const newPhoto = /** @type {HTMLImageElement} */ (jml('img', {
923
+ const newPhoto = jml('img', {
913
924
  class: 'photo'
914
- }));
925
+ });
915
926
  const url = URL.createObjectURL(blob);
916
927
 
917
928
  newPhoto.addEventListener('load', () => {
@@ -951,9 +962,9 @@ const blobType = {
951
962
  {class: 'recordedMedia'},
952
963
  /** @type {import('jamilih').JamilihChildren} */ ([
953
964
  ...(() => {
954
- const recordedMedia = /** @type {HTMLVideoElement} */ (jml(
965
+ const recordedMedia = jml(
955
966
  'video', {class: 'recordedMedia'}
956
- ));
967
+ );
957
968
  return [
958
969
  recordedMedia,
959
970
  ['br'],