@es-joy/jsoe 0.15.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 (207) hide show
  1. package/.ncurc.cjs +4 -5
  2. package/CHANGES.md +9 -0
  3. package/README.md +28 -4
  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 +9661 -1587
  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 +59 -69
  124. package/rollup.config.js +16 -1
  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 +52 -34
  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 -114984
  202. package/cypress.config.ts +0 -15
  203. package/demo/index-instrumented.html +0 -29
  204. package/demo/index.html +0 -29
  205. package/demo/index.js +0 -644
  206. package/src/formats/schemaAndArbitrary.js +0 -20
  207. package/src/formats/schemaOnly.js +0 -539
@@ -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';
@@ -168,6 +168,9 @@ function binaryButton (value, editable) {
168
168
  const fileType = {
169
169
  option: ['File'],
170
170
  stringRegex: /^File\((.*)\)$/u,
171
+ valueMatch (x) {
172
+ return toStringTag(x) === 'File';
173
+ },
171
174
  toValue (s) {
172
175
  const obj = JSON.parse(s);
173
176
  return {value: new File([obj.stringContents], obj.name, {
@@ -189,10 +192,13 @@ const fileType = {
189
192
  this.getInput({root})
190
193
  ).$value;
191
194
  },
192
- viewUI ({value}) {
195
+ viewUI ({value, specificSchemaObject}) {
193
196
  return ['div', {dataset: {type: 'file'}}, [
194
- ['b', {class: 'emphasis'}, [
195
- 'File'
197
+ ['b', {
198
+ class: 'emphasis',
199
+ title: specificSchemaObject?.description ? '(a File)' : undefined
200
+ }, [
201
+ specificSchemaObject?.description ?? 'File'
196
202
  ]],
197
203
  ['br'],
198
204
  ['br'],
@@ -218,7 +224,7 @@ const fileType = {
218
224
  ['br'],
219
225
  value.type.startsWith('text/') || value.type === 'application/json'
220
226
  ? (() => {
221
- const div = /** @type {HTMLDivElement} */ (jml('div'));
227
+ const div = jml('div');
222
228
  const reader = new FileReader();
223
229
  reader.addEventListener('load', function () {
224
230
  div.append(jml('div', [
@@ -250,7 +256,7 @@ const fileType = {
250
256
  value.type.startsWith('video/')
251
257
  ? (() => {
252
258
  const objURL = URL.createObjectURL(value);
253
- const video = /** @type {HTMLVideoElement} */ (jml('video', {
259
+ const video = jml('video', {
254
260
  src: objURL,
255
261
  class: 'video',
256
262
  $on: {
@@ -258,7 +264,7 @@ const fileType = {
258
264
  URL.revokeObjectURL(objURL);
259
265
  }
260
266
  }
261
- }));
267
+ });
262
268
 
263
269
  return ['div', [
264
270
  video,
@@ -303,7 +309,7 @@ const fileType = {
303
309
  value.type.startsWith('audio/')
304
310
  ? (() => {
305
311
  const objURL = URL.createObjectURL(value);
306
- const audio = /** @type {HTMLAudioElement} */ (jml('audio', {
312
+ const audio = jml('audio', {
307
313
  src: objURL,
308
314
  class: 'audio',
309
315
  $on: {
@@ -311,7 +317,7 @@ const fileType = {
311
317
  URL.revokeObjectURL(objURL);
312
318
  }
313
319
  }
314
- }));
320
+ });
315
321
  return ['div', [
316
322
  audio,
317
323
  ['button', {
@@ -382,10 +388,13 @@ const fileType = {
382
388
  : ''
383
389
  ]];
384
390
  },
385
- editUI ({typeNamespace, value = {}}) {
391
+ editUI ({typeNamespace, specificSchemaObject, value = {}}) {
386
392
  // Todo: Could add way to preview file in edit mode (whether
387
393
  // recorded or uploaded)
388
- return ['div', {dataset: {type: 'file'}}, [
394
+ return ['div', {
395
+ dataset: {type: 'file'},
396
+ title: specificSchemaObject?.description ?? 'File'
397
+ }, [
389
398
  ['fieldset', {
390
399
  class: 'fileMetaData',
391
400
  $custom: {
@@ -456,7 +465,7 @@ const fileType = {
456
465
  ['label', [
457
466
  'Size (in bytes) ',
458
467
  ['input', {
459
- type: 'number', disabled: true, class: 'size',
468
+ type: 'number', step: '1', disabled: true, class: 'size',
460
469
  value: String(value.size)
461
470
  }]
462
471
  ]],
@@ -576,194 +585,192 @@ const fileType = {
576
585
  'Supply file through recording'
577
586
  ]],
578
587
  (() => {
579
- const select = /** @type {HTMLSelectElement} */ (
580
- jml('select', {
581
- class: 'device',
582
- $on: {
583
- async change () {
584
- const videoContainer = /** @type {HTMLDivElement} */ (
585
- this.nextElementSibling?.nextElementSibling
586
- );
588
+ const select = jml('select', {
589
+ class: 'device',
590
+ $on: {
591
+ async change () {
592
+ const videoContainer = /** @type {HTMLDivElement} */ (
593
+ this.nextElementSibling?.nextElementSibling
594
+ );
587
595
 
588
- const photo =
589
- /**
590
- * @type {HTMLCanvasElement}
591
- */
592
- ($e(videoContainer, 'img.photo'));
593
- photo.hidden = true;
594
-
595
- const oldVideo =
596
- /**
597
- * @type {HTMLVideoElement & {
598
- * $stream: MediaStream
599
- * }}
600
- */
601
- ($e(
602
- videoContainer,
603
- 'video.previewMedia'
604
- ));
605
-
606
- // Drop preexisting listeners
607
- const previewMedia =
608
- /**
609
- * @type {HTMLVideoElement & {
610
- * $stream: MediaStream,
611
- * $screenShare: boolean
612
- * }}
613
- */ (
614
- jml('video', {
615
- class: 'previewMedia'
616
- })
617
- );
618
-
619
- if (oldVideo.$stream) {
620
- const tracks = /** @type {MediaStream} */ (
621
- oldVideo.$stream
622
- ).getTracks();
623
- tracks.forEach((track) => {
624
- track.stop();
625
- });
626
- oldVideo.srcObject = null;
627
- }
596
+ const photo =
597
+ /**
598
+ * @type {HTMLCanvasElement}
599
+ */
600
+ ($e(videoContainer, 'img.photo'));
601
+ photo.hidden = true;
628
602
 
629
- oldVideo.replaceWith(previewMedia);
603
+ const oldVideo =
604
+ /**
605
+ * @type {HTMLVideoElement & {
606
+ * $stream: MediaStream
607
+ * }}
608
+ */
609
+ ($e(
610
+ videoContainer,
611
+ 'video.previewMedia'
612
+ ));
630
613
 
631
- const takeSnapshot = /** @type {HTMLButtonElement} */ (
632
- $e(/** @type {HTMLDivElement} */ (
633
- select.nextElementSibling
634
- ), '.takeSnapshot')
614
+ // Drop preexisting listeners
615
+ const previewMedia =
616
+ /**
617
+ * @type {HTMLVideoElement & {
618
+ * $stream: MediaStream,
619
+ * $screenShare: boolean
620
+ * }}
621
+ */ (
622
+ jml('video', {
623
+ class: 'previewMedia'
624
+ })
635
625
  );
636
626
 
637
- const recordMedia = /** @type {HTMLButtonElement} */ (
638
- $e(/** @type {HTMLDivElement} */ (
639
- select.nextElementSibling
640
- ), '.recordMedia')
641
- );
627
+ if (oldVideo.$stream) {
628
+ const tracks = /** @type {MediaStream} */ (
629
+ oldVideo.$stream
630
+ ).getTracks();
631
+ tracks.forEach((track) => {
632
+ track.stop();
633
+ });
634
+ oldVideo.srcObject = null;
635
+ }
642
636
 
643
- /** @type {HTMLDivElement} */ ($e(
644
- /** @type {HTMLDivElement} */
645
- (select.nextElementSibling?.
646
- nextElementSibling),
647
- 'div.recordedMedia'
648
- )).hidden = true;
637
+ oldVideo.replaceWith(previewMedia);
649
638
 
650
- const visualizer = /** @type {HTMLCanvasElement} */ (
651
- $e(videoContainer, 'canvas.visualizer')
652
- );
639
+ const takeSnapshot = /** @type {HTMLButtonElement} */ (
640
+ $e(/** @type {HTMLDivElement} */ (
641
+ select.nextElementSibling
642
+ ), '.takeSnapshot')
643
+ );
653
644
 
654
- /**
655
- * @type {{
656
- * video?: true,
657
- * audio?: true
658
- * }|undefined}
659
- */
660
- let constraints;
661
- let screenShareConstraints;
662
-
663
- previewMedia.$screenShare = false;
664
- switch (select.value) {
665
- case 'audio-and-video':
666
- constraints = {video: true, audio: true};
667
- previewMedia.hidden = false;
668
- takeSnapshot.hidden = false;
669
- recordMedia.textContent = 'Record video/audio';
670
- break;
671
- case 'video':
672
- constraints = {video: true};
673
- previewMedia.hidden = false;
674
- takeSnapshot.hidden = false;
675
- recordMedia.textContent = 'Record video';
676
- break;
677
- case 'audio':
678
- constraints = {audio: true};
679
- previewMedia.hidden = true;
680
- takeSnapshot.hidden = true;
681
- recordMedia.textContent = 'Record audio';
682
- break;
683
- case 'screenShare':
684
- screenShareConstraints = {video: true};
685
- // Fallthrough
686
- case 'screenShareAndVideo':
687
- if (!screenShareConstraints) {
688
- screenShareConstraints = {video: true, audio: true};
689
- }
690
- previewMedia.$screenShare = true;
691
- previewMedia.hidden = true;
692
- takeSnapshot.hidden = true;
693
- visualizer.hidden = true;
694
- break;
695
- default:
696
- return;
697
- }
645
+ const recordMedia = /** @type {HTMLButtonElement} */ (
646
+ $e(/** @type {HTMLDivElement} */ (
647
+ select.nextElementSibling
648
+ ), '.recordMedia')
649
+ );
698
650
 
699
- if (constraints) {
700
- const mediaStream = await getUserMedia(constraints);
701
- /* istanbul ignore if */
702
- if (!mediaStream) {
703
- await dialogs.alert('Error getting user media');
704
- return;
705
- }
651
+ /** @type {HTMLDivElement} */ ($e(
652
+ /** @type {HTMLDivElement} */
653
+ (select.nextElementSibling?.
654
+ nextElementSibling),
655
+ 'div.recordedMedia'
656
+ )).hidden = true;
706
657
 
707
- videoContainer.hidden = false;
708
- previewMedia.srcObject = mediaStream;
709
-
710
- // Save as stream for later reuse as stream
711
- previewMedia.$stream = mediaStream;
712
-
713
- if (constraints.video) {
714
- const canvas =
715
- /**
716
- * @type {HTMLCanvasElement}
717
- */
718
- ($e(
719
- videoContainer,
720
- 'canvas.recordedImage'
721
- ));
722
- // https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Taking_still_photos
723
- previewMedia.addEventListener('canplay', () => {
724
- canvas.setAttribute('width', String(
725
- previewMedia.videoWidth
726
- ));
727
- canvas.setAttribute(
728
- 'height', String(previewMedia.videoHeight)
729
- );
730
- });
731
- }
658
+ const visualizer = /** @type {HTMLCanvasElement} */ (
659
+ $e(videoContainer, 'canvas.visualizer')
660
+ );
732
661
 
733
- previewMedia.addEventListener('loadedmetadata', () => {
734
- previewMedia.play();
735
- if (constraints?.audio) {
736
- visualizer.hidden = false;
737
- visualize(
738
- mediaStream,
739
- visualizer
740
- );
741
- } else {
742
- visualizer.hidden = true;
743
- }
662
+ /**
663
+ * @type {{
664
+ * video?: true,
665
+ * audio?: true
666
+ * }|undefined}
667
+ */
668
+ let constraints;
669
+ let screenShareConstraints;
670
+
671
+ previewMedia.$screenShare = false;
672
+ switch (select.value) {
673
+ case 'audio-and-video':
674
+ constraints = {video: true, audio: true};
675
+ previewMedia.hidden = false;
676
+ takeSnapshot.hidden = false;
677
+ recordMedia.textContent = 'Record video/audio';
678
+ break;
679
+ case 'video':
680
+ constraints = {video: true};
681
+ previewMedia.hidden = false;
682
+ takeSnapshot.hidden = false;
683
+ recordMedia.textContent = 'Record video';
684
+ break;
685
+ case 'audio':
686
+ constraints = {audio: true};
687
+ previewMedia.hidden = true;
688
+ takeSnapshot.hidden = true;
689
+ recordMedia.textContent = 'Record audio';
690
+ break;
691
+ case 'screenShare':
692
+ screenShareConstraints = {video: true};
693
+ // Fallthrough
694
+ case 'screenShareAndVideo':
695
+ if (!screenShareConstraints) {
696
+ screenShareConstraints = {video: true, audio: true};
697
+ }
698
+ previewMedia.$screenShare = true;
699
+ previewMedia.hidden = true;
700
+ takeSnapshot.hidden = true;
701
+ visualizer.hidden = true;
702
+ break;
703
+ default:
704
+ return;
705
+ }
706
+
707
+ if (constraints) {
708
+ const mediaStream = await getUserMedia(constraints);
709
+ /* istanbul ignore if */
710
+ if (!mediaStream) {
711
+ await dialogs.alert('Error getting user media');
712
+ return;
713
+ }
714
+
715
+ videoContainer.hidden = false;
716
+ previewMedia.srcObject = mediaStream;
717
+
718
+ // Save as stream for later reuse as stream
719
+ previewMedia.$stream = mediaStream;
720
+
721
+ if (constraints.video) {
722
+ const canvas =
723
+ /**
724
+ * @type {HTMLCanvasElement}
725
+ */
726
+ ($e(
727
+ videoContainer,
728
+ 'canvas.recordedImage'
729
+ ));
730
+ // https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Taking_still_photos
731
+ previewMedia.addEventListener('canplay', () => {
732
+ canvas.setAttribute('width', String(
733
+ previewMedia.videoWidth
734
+ ));
735
+ canvas.setAttribute(
736
+ 'height', String(previewMedia.videoHeight)
737
+ );
744
738
  });
745
- } else if (screenShareConstraints) {
746
- const mediaStream = await startScreenCapture(
747
- screenShareConstraints
748
- );
749
- /* istanbul ignore if */
750
- if (!mediaStream) {
751
- await dialogs.alert('Error getting user media');
752
- return;
739
+ }
740
+
741
+ previewMedia.addEventListener('loadedmetadata', () => {
742
+ previewMedia.play();
743
+ if (constraints?.audio) {
744
+ visualizer.hidden = false;
745
+ visualize(
746
+ mediaStream,
747
+ visualizer
748
+ );
749
+ } else {
750
+ visualizer.hidden = true;
753
751
  }
752
+ });
753
+ } else if (screenShareConstraints) {
754
+ const mediaStream = await startScreenCapture(
755
+ screenShareConstraints
756
+ );
757
+ /* istanbul ignore if */
758
+ if (!mediaStream) {
759
+ await dialogs.alert('Error getting user media');
760
+ return;
761
+ }
754
762
 
755
- videoContainer.hidden = false;
756
- previewMedia.srcObject = mediaStream;
763
+ videoContainer.hidden = false;
764
+ previewMedia.srcObject = mediaStream;
757
765
 
758
- // Save as stream for later reuse as stream
759
- previewMedia.$stream = mediaStream;
760
- }
766
+ // Save as stream for later reuse as stream
767
+ previewMedia.$stream = mediaStream;
761
768
  }
762
769
  }
763
- }, [
764
- ['option', {value: ''}, ['Please choose a device']]
765
- ])
766
- );
770
+ }
771
+ }, [
772
+ ['option', {value: ''}, ['Please choose a device']]
773
+ ]);
767
774
 
768
775
  (async () => {
769
776
  const devices = await navigator.mediaDevices.enumerateDevices();
@@ -864,8 +871,7 @@ const fileType = {
864
871
 
865
872
  try {
866
873
  mediaRecorder.start();
867
- /* istanbul ignore if */
868
- } catch (err) {
874
+ } catch /* istanbul ignore next */ {
869
875
  dialogs.alert('Error starting media recorder');
870
876
  return;
871
877
  }
@@ -1009,9 +1015,9 @@ const fileType = {
1009
1015
  dialogs.alert('Error converting canvas to Blob');
1010
1016
  return;
1011
1017
  }
1012
- const newPhoto = /** @type {HTMLImageElement} */ (jml('img', {
1018
+ const newPhoto = jml('img', {
1013
1019
  class: 'photo'
1014
- }));
1020
+ });
1015
1021
  const url = URL.createObjectURL(blob);
1016
1022
 
1017
1023
  newPhoto.addEventListener('load', () => {
@@ -1058,9 +1064,9 @@ const fileType = {
1058
1064
  {class: 'recordedMedia'},
1059
1065
  /** @type {import('jamilih').JamilihChildren} */ ([
1060
1066
  ...(() => {
1061
- const recordedMedia = /** @type {HTMLVideoElement} */ (jml(
1067
+ const recordedMedia = jml(
1062
1068
  'video', {class: 'recordedMedia'}
1063
- ));
1069
+ );
1064
1070
  return [
1065
1071
  recordedMedia,
1066
1072
  ['br'],
@@ -1,3 +1,4 @@
1
+ import {toStringTag} from '../vendor-imports.js';
1
2
  import arrayType from './arrayType.js';
2
3
 
3
4
  /**
@@ -10,6 +11,9 @@ const filelistType = {
10
11
  regexEndings: [',', ')'],
11
12
  stringRegexBegin: /^FileList\(/u,
12
13
  stringRegexEnd: /^\)/u,
14
+ valueMatch (x) {
15
+ return toStringTag(x) === 'FileList';
16
+ },
13
17
 
14
18
  toValue (...args) {
15
19
  return /** @type {import('../types.js').ToValue} */ (
@@ -0,0 +1,150 @@
1
+ import {$e} from '../utils/templateUtils.js';
2
+ import {copyObject} from '../utils/objects.js';
3
+
4
+ /**
5
+ * @type {import('../types.js').TypeObject}
6
+ */
7
+ const functionType = {
8
+ option: ['function'],
9
+ stringRegex: /^function\((.*)\): (.*)$/u,
10
+ // Todo: Fix all the following methods up to `editUI` to work with children
11
+ valueMatch (x) {
12
+ return typeof x === 'function';
13
+ },
14
+ toValue (s) {
15
+ return {value: s.slice(8, -1)};
16
+ },
17
+ getInput ({root}) {
18
+ return /** @type {HTMLTextAreaElement} */ ($e(root, 'input'));
19
+ },
20
+ setValue ({root, value}) {
21
+ this.getInput({root}).value = value;
22
+ },
23
+ getValue ({root}) {
24
+ return this.getInput({root}).value;
25
+ },
26
+ viewUI ({value, specificSchemaObject}) {
27
+ return ['span', {
28
+ dataset: {type: 'function'},
29
+ title: specificSchemaObject?.description ?? '(a function)'
30
+ }, [value]];
31
+ },
32
+ editUI ({
33
+ format, type, buildTypeChoices, specificSchemaObject,
34
+ topRoot, // schemaContent,
35
+ typeNamespace
36
+ }) {
37
+ // Todo: Support `getValue`; add to demo with tests; could also add to
38
+ // use with `Promise` so that could also build a meaningful
39
+ // implementation; use schema to inform user of types of args,
40
+ // but remember we are not reimplementing the function schema to
41
+ // ask for argument types, etc.
42
+
43
+ // We want to allow overriding its descriptions
44
+ const specificSchemaObj = copyObject(specificSchemaObject);
45
+ const argsTuple = /** @type {import('zodex').SzFunction<any, any>} */ (
46
+ specificSchemaObj
47
+ )?.args ?? {type: 'tuple', items: [], rest: {type: 'any'}};
48
+ argsTuple.description = '';
49
+ // This `description` not in use, but could support
50
+ if (argsTuple.rest) {
51
+ argsTuple.rest.description = 'Argument';
52
+ }
53
+
54
+ const size = argsTuple.items.length + (argsTuple.rest ? 1 : 0);
55
+ const args = /** @type {import('zodex').SzType} */ (
56
+ {
57
+ type: 'set',
58
+ minSize: size,
59
+ maxSize: size,
60
+ value: {
61
+ type: 'string',
62
+ // See https://github.com/tc39/proposal-regexp-unicode-property-escapes#other-examples
63
+ // eslint-disable-next-line @stylistic/max-len -- Long
64
+ regex: String.raw`^(?:[$_\p{ID_Start}])(?:[$_\u200C\u200D\p{ID_Continue}])*$`,
65
+ flags: 'v'
66
+ }
67
+ }
68
+ );
69
+
70
+ return ['div', {dataset: {type: 'function'}}, [
71
+ ['b', ['Arguments']],
72
+ ['br'],
73
+
74
+ // This was working to allow choice of specific function argument types,
75
+ // but we want function argument names to build a real function; the
76
+ // specific attached schema should already specify function argument
77
+ // types.
78
+ // ...(/** @type {import('../typeChoices.js').BuildTypeChoices} */ (
79
+ // buildTypeChoices
80
+ // )({
81
+ // // resultType,
82
+ // // eslint-disable-next-line object-shorthand -- TS
83
+ // topRoot: /** @type {HTMLDivElement} */ (topRoot),
84
+ // // eslint-disable-next-line object-shorthand -- TS
85
+ // format:
86
+ // /** @type {import('../formats.js').AvailableFormat} */ (format),
87
+ // schemaOriginal: schemaContent,
88
+ // schemaContent: argsTuple,
89
+ // state: type,
90
+ // // itemIndex,
91
+ // typeNamespace
92
+ // }).domArray),
93
+
94
+ ...(/** @type {import('../typeChoices.js').BuildTypeChoices} */ (
95
+ buildTypeChoices
96
+ )({
97
+ // resultType,
98
+ // eslint-disable-next-line object-shorthand -- TS
99
+ topRoot: /** @type {HTMLDivElement} */ (topRoot),
100
+ // eslint-disable-next-line object-shorthand -- TS
101
+ format: /** @type {import('../formats.js').AvailableFormat} */ (format),
102
+ // schemaOriginal: schemaContent,
103
+ schemaContent: args,
104
+ state: type,
105
+ // itemIndex,
106
+ typeNamespace
107
+ }).domArray),
108
+
109
+ ['b', ['Function body']],
110
+ ['br'],
111
+ ...(/** @type {import('../typeChoices.js').BuildTypeChoices} */ (
112
+ buildTypeChoices
113
+ )({
114
+ // resultType,
115
+ // eslint-disable-next-line object-shorthand -- TS
116
+ topRoot: /** @type {HTMLDivElement} */ (topRoot),
117
+ // eslint-disable-next-line object-shorthand -- TS
118
+ format: /** @type {import('../formats.js').AvailableFormat} */ (format),
119
+ // schemaOriginal: schemaContent,
120
+ schemaContent: {type: 'string'},
121
+ state: type,
122
+ // itemIndex,
123
+ typeNamespace
124
+ }).domArray)
125
+
126
+ // This was previously working (see commented out block above)
127
+ // ['b', ['Returns']],
128
+ // ['br'],
129
+ // ...(/** @type {import('../typeChoices.js').BuildTypeChoices} */ (
130
+ // buildTypeChoices
131
+ // )({
132
+ // // resultType,
133
+ // // eslint-disable-next-line object-shorthand -- TS
134
+ // topRoot: /** @type {HTMLDivElement} */ (topRoot),
135
+ // // eslint-disable-next-line object-shorthand -- TS
136
+ // format:
137
+ // /** @type {import('../formats.js').AvailableFormat} */ (format),
138
+ // schemaOriginal: schemaContent,
139
+ // schemaContent: /** @type {import('zodex').SzFunction<any, any>} */ (
140
+ // specificSchemaObj
141
+ // )?.returns ?? {type: 'any'},
142
+ // state: type,
143
+ // // itemIndex,
144
+ // typeNamespace
145
+ // }).domArray)
146
+ ]];
147
+ }
148
+ };
149
+
150
+ export default functionType;