@bendyline/squisq-editor-react 2.4.5 → 2.4.7
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 +8 -1
- package/dist/{chunk-PEI5EBEN.js → chunk-4F7SN6WU.js} +1 -1
- package/dist/{chunk-7OKWPWEQ.js → chunk-55DQFHK5.js} +184 -48
- package/dist/{chunk-V6Z7GG55.js → chunk-IQFPX2CE.js} +1 -1
- package/dist/{chunk-WLJ623UZ.js → chunk-K2WJYVS4.js} +7 -6
- package/dist/{chunk-PDCKJCOS.js → chunk-OWOKKZAU.js} +43 -11
- package/dist/{chunk-WDX6UDL5.js → chunk-YPRX32GY.js} +1 -1
- package/dist/{chunk-PKGBWNUQ.js → chunk-ZSQN6IO7.js} +1061 -141
- package/dist/index.d.ts +7 -9
- package/dist/index.js +21 -7
- package/dist/json-editor/index.js +2 -2
- package/dist/recorder/index.d.ts +2 -2
- package/dist/recorder/index.js +17 -3
- package/dist/{recorder-C0Tkyu5W.d.ts → recorder-CnOKlYY3.d.ts} +96 -202
- package/dist/shell/index.js +5 -5
- package/dist/teleprompter/index.d.ts +2 -2
- package/dist/teleprompter/index.js +2 -2
- package/dist/useNarrationStage-Bk3mdW75.d.ts +560 -0
- package/package.json +4 -4
- package/dist/useNarrationStage-Bqo18PBw.d.ts +0 -313
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
timingPathFor,
|
|
17
17
|
useNarrationStage,
|
|
18
18
|
useStreamPreview
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-OWOKKZAU.js";
|
|
20
20
|
|
|
21
21
|
// src/recorder/sources/screenStream.ts
|
|
22
22
|
function mixAudioTracks(streams) {
|
|
@@ -43,7 +43,7 @@ async function requestScreenStream(options) {
|
|
|
43
43
|
const includeMic = options?.includeMicrophone ?? false;
|
|
44
44
|
const displayStream = await navigator.mediaDevices.getDisplayMedia({
|
|
45
45
|
video,
|
|
46
|
-
audio: systemAudio
|
|
46
|
+
audio: systemAudio ? options?.systemAudioConstraints ?? true : false
|
|
47
47
|
});
|
|
48
48
|
if (!includeMic) {
|
|
49
49
|
return {
|
|
@@ -100,11 +100,14 @@ async function requestScreenStream(options) {
|
|
|
100
100
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
101
101
|
|
|
102
102
|
// src/recorder/sources/systemAudioStream.ts
|
|
103
|
-
async function requestSystemAudioStream() {
|
|
103
|
+
async function requestSystemAudioStream(audioConstraints) {
|
|
104
104
|
if (!supportsDisplayMedia()) {
|
|
105
105
|
throw new Error("navigator.mediaDevices.getDisplayMedia is not available in this environment.");
|
|
106
106
|
}
|
|
107
|
-
const display = await navigator.mediaDevices.getDisplayMedia({
|
|
107
|
+
const display = await navigator.mediaDevices.getDisplayMedia({
|
|
108
|
+
video: true,
|
|
109
|
+
audio: audioConstraints ?? true
|
|
110
|
+
});
|
|
108
111
|
display.getVideoTracks().forEach((t) => t.stop());
|
|
109
112
|
const audio = display.getAudioTracks();
|
|
110
113
|
if (audio.length === 0) return null;
|
|
@@ -152,7 +155,7 @@ async function acquireStream(source, opts) {
|
|
|
152
155
|
case "mic": {
|
|
153
156
|
const audio = typeof opts.audioConstraints === "object" ? opts.audioConstraints : void 0;
|
|
154
157
|
if (opts.systemAudio) {
|
|
155
|
-
const systemAudio = await requestSystemAudioStream();
|
|
158
|
+
const systemAudio = await requestSystemAudioStream(opts.screenAudioConstraints);
|
|
156
159
|
let base;
|
|
157
160
|
try {
|
|
158
161
|
base = await requestMicStream(audio);
|
|
@@ -172,7 +175,7 @@ async function acquireStream(source, opts) {
|
|
|
172
175
|
const video = opts.videoConstraints ?? true;
|
|
173
176
|
const audio = opts.includeMicrophone === false ? false : opts.audioConstraints ?? true;
|
|
174
177
|
if (opts.systemAudio) {
|
|
175
|
-
const systemAudio = await requestSystemAudioStream();
|
|
178
|
+
const systemAudio = await requestSystemAudioStream(opts.screenAudioConstraints);
|
|
176
179
|
let base;
|
|
177
180
|
try {
|
|
178
181
|
base = await requestCameraStream({ video, audio });
|
|
@@ -191,8 +194,9 @@ async function acquireStream(source, opts) {
|
|
|
191
194
|
case "screen":
|
|
192
195
|
case "screen+mic": {
|
|
193
196
|
const handle = await requestScreenStream({
|
|
194
|
-
video: opts.videoConstraints ?? true,
|
|
197
|
+
video: opts.screenVideoConstraints ?? opts.videoConstraints ?? true,
|
|
195
198
|
systemAudio: opts.systemAudio ?? false,
|
|
199
|
+
systemAudioConstraints: opts.screenAudioConstraints,
|
|
196
200
|
includeMicrophone: source === "screen+mic",
|
|
197
201
|
microphoneConstraints: typeof opts.audioConstraints === "object" ? opts.audioConstraints : void 0
|
|
198
202
|
});
|
|
@@ -202,8 +206,9 @@ async function acquireStream(source, opts) {
|
|
|
202
206
|
}
|
|
203
207
|
async function acquireDualStreams(opts, isStale) {
|
|
204
208
|
const screen = await requestScreenStream({
|
|
205
|
-
video: opts.videoConstraints ?? true,
|
|
209
|
+
video: opts.screenVideoConstraints ?? opts.videoConstraints ?? true,
|
|
206
210
|
systemAudio: opts.systemAudio ?? false,
|
|
211
|
+
systemAudioConstraints: opts.screenAudioConstraints,
|
|
207
212
|
includeMicrophone: false
|
|
208
213
|
});
|
|
209
214
|
const releaseScreen = () => {
|
|
@@ -217,7 +222,7 @@ async function acquireDualStreams(opts, isStale) {
|
|
|
217
222
|
let camera;
|
|
218
223
|
try {
|
|
219
224
|
camera = await requestCameraStream({
|
|
220
|
-
video: true,
|
|
225
|
+
video: opts.videoConstraints ?? true,
|
|
221
226
|
audio: opts.includeMicrophone === false ? false : opts.audioConstraints ?? true
|
|
222
227
|
});
|
|
223
228
|
} catch (err) {
|
|
@@ -381,6 +386,20 @@ function useMediaRecorder(options = {}) {
|
|
|
381
386
|
if (optionsRef.current.bitsPerSecond) {
|
|
382
387
|
recorderOptions.bitsPerSecond = optionsRef.current.bitsPerSecond;
|
|
383
388
|
}
|
|
389
|
+
if (optionsRef.current.audioBitsPerSecond) {
|
|
390
|
+
recorderOptions.audioBitsPerSecond = optionsRef.current.audioBitsPerSecond;
|
|
391
|
+
}
|
|
392
|
+
if (optionsRef.current.videoBitsPerSecond) {
|
|
393
|
+
recorderOptions.videoBitsPerSecond = optionsRef.current.videoBitsPerSecond;
|
|
394
|
+
}
|
|
395
|
+
if (optionsRef.current.audioBitrateMode) {
|
|
396
|
+
recorderOptions.audioBitrateMode = optionsRef.current.audioBitrateMode;
|
|
397
|
+
}
|
|
398
|
+
if (optionsRef.current.videoKeyFrameIntervalDuration) {
|
|
399
|
+
recorderOptions.videoKeyFrameIntervalDuration = optionsRef.current.videoKeyFrameIntervalDuration;
|
|
400
|
+
} else if (optionsRef.current.videoKeyFrameIntervalCount) {
|
|
401
|
+
recorderOptions.videoKeyFrameIntervalCount = optionsRef.current.videoKeyFrameIntervalCount;
|
|
402
|
+
}
|
|
384
403
|
if (source === "screen+camera") {
|
|
385
404
|
dual = await acquireDualStreams(
|
|
386
405
|
optionsRef.current,
|
|
@@ -699,14 +718,818 @@ function useMediaRecorder(options = {}) {
|
|
|
699
718
|
};
|
|
700
719
|
}
|
|
701
720
|
|
|
721
|
+
// src/recorder/RecorderDeviceSettingsPanel.tsx
|
|
722
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useId, useState as useState2 } from "react";
|
|
723
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
724
|
+
var detailsStyle = {
|
|
725
|
+
border: "1px solid var(--squisq-recorder-border)",
|
|
726
|
+
marginBottom: 12
|
|
727
|
+
};
|
|
728
|
+
var summaryToggleStyle = {
|
|
729
|
+
cursor: "pointer",
|
|
730
|
+
padding: "8px 10px",
|
|
731
|
+
fontSize: 13,
|
|
732
|
+
fontWeight: 600,
|
|
733
|
+
color: "var(--squisq-recorder-text)",
|
|
734
|
+
background: "var(--squisq-recorder-surface-muted)"
|
|
735
|
+
};
|
|
736
|
+
var panelStyle = {
|
|
737
|
+
padding: "4px 10px 10px"
|
|
738
|
+
};
|
|
739
|
+
var fieldsetStyle = {
|
|
740
|
+
border: 0,
|
|
741
|
+
borderTop: "1px solid var(--squisq-recorder-border)",
|
|
742
|
+
margin: "10px 0 0",
|
|
743
|
+
padding: "10px 0 0"
|
|
744
|
+
};
|
|
745
|
+
var legendStyle = {
|
|
746
|
+
padding: "0 6px 0 0",
|
|
747
|
+
fontSize: 12,
|
|
748
|
+
fontWeight: 700,
|
|
749
|
+
color: "var(--squisq-recorder-text)"
|
|
750
|
+
};
|
|
751
|
+
var gridStyle = {
|
|
752
|
+
display: "grid",
|
|
753
|
+
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
|
|
754
|
+
gap: "8px 10px"
|
|
755
|
+
};
|
|
756
|
+
var fieldStyle = {
|
|
757
|
+
display: "flex",
|
|
758
|
+
flexDirection: "column",
|
|
759
|
+
gap: 3,
|
|
760
|
+
minWidth: 0,
|
|
761
|
+
fontSize: 12,
|
|
762
|
+
color: "var(--squisq-recorder-muted)"
|
|
763
|
+
};
|
|
764
|
+
var inputStyle = {
|
|
765
|
+
width: "100%",
|
|
766
|
+
minWidth: 0,
|
|
767
|
+
boxSizing: "border-box",
|
|
768
|
+
padding: "5px 6px",
|
|
769
|
+
font: "inherit",
|
|
770
|
+
color: "var(--squisq-recorder-text)",
|
|
771
|
+
background: "var(--squisq-recorder-input)",
|
|
772
|
+
border: "1px solid var(--squisq-recorder-border)"
|
|
773
|
+
};
|
|
774
|
+
var noteStyle = {
|
|
775
|
+
margin: "8px 0 0",
|
|
776
|
+
fontSize: 11,
|
|
777
|
+
lineHeight: 1.4,
|
|
778
|
+
color: "var(--squisq-recorder-muted)"
|
|
779
|
+
};
|
|
780
|
+
var actualStyle = {
|
|
781
|
+
margin: "6px 0 0",
|
|
782
|
+
padding: 6,
|
|
783
|
+
overflowX: "auto",
|
|
784
|
+
fontSize: 10,
|
|
785
|
+
lineHeight: 1.35,
|
|
786
|
+
color: "var(--squisq-recorder-muted)",
|
|
787
|
+
background: "var(--squisq-recorder-surface-muted)"
|
|
788
|
+
};
|
|
789
|
+
var AUDIO_MIME_TYPES = [
|
|
790
|
+
"audio/webm;codecs=opus",
|
|
791
|
+
"audio/webm",
|
|
792
|
+
"audio/mp4",
|
|
793
|
+
"audio/ogg;codecs=opus"
|
|
794
|
+
];
|
|
795
|
+
var VIDEO_MIME_TYPES = [
|
|
796
|
+
"video/webm;codecs=vp9,opus",
|
|
797
|
+
"video/webm;codecs=vp8,opus",
|
|
798
|
+
"video/webm",
|
|
799
|
+
"video/mp4"
|
|
800
|
+
];
|
|
801
|
+
function numberFromInput(value) {
|
|
802
|
+
if (value.trim() === "") return void 0;
|
|
803
|
+
const number = Number(value);
|
|
804
|
+
return Number.isFinite(number) && number > 0 ? number : void 0;
|
|
805
|
+
}
|
|
806
|
+
function triState(value) {
|
|
807
|
+
return value === void 0 ? "default" : value ? "true" : "false";
|
|
808
|
+
}
|
|
809
|
+
function booleanFromTriState(value) {
|
|
810
|
+
return value === "default" ? void 0 : value === "true";
|
|
811
|
+
}
|
|
812
|
+
function deviceLabel(device, index, noun) {
|
|
813
|
+
return device.label || `${noun} ${index + 1}`;
|
|
814
|
+
}
|
|
815
|
+
function deviceGroups(devices) {
|
|
816
|
+
const groups = /* @__PURE__ */ new Map();
|
|
817
|
+
for (const [index, device] of devices.entries()) {
|
|
818
|
+
if (!device.groupId || groups.has(device.groupId)) continue;
|
|
819
|
+
groups.set(device.groupId, device.label || `Device group ${index + 1}`);
|
|
820
|
+
}
|
|
821
|
+
return [...groups].map(([id, label]) => ({ id, label }));
|
|
822
|
+
}
|
|
823
|
+
function readSettings(track) {
|
|
824
|
+
if (!track || typeof track.getSettings !== "function") return null;
|
|
825
|
+
try {
|
|
826
|
+
return track.getSettings();
|
|
827
|
+
} catch {
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
function NumericField({
|
|
832
|
+
label,
|
|
833
|
+
value,
|
|
834
|
+
onChange,
|
|
835
|
+
disabled,
|
|
836
|
+
min,
|
|
837
|
+
step
|
|
838
|
+
}) {
|
|
839
|
+
return /* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
840
|
+
label,
|
|
841
|
+
/* @__PURE__ */ jsx(
|
|
842
|
+
"input",
|
|
843
|
+
{
|
|
844
|
+
type: "number",
|
|
845
|
+
min: min ?? 0,
|
|
846
|
+
step: step ?? 1,
|
|
847
|
+
value: value ?? "",
|
|
848
|
+
disabled,
|
|
849
|
+
style: inputStyle,
|
|
850
|
+
onChange: (event) => onChange(numberFromInput(event.target.value))
|
|
851
|
+
}
|
|
852
|
+
)
|
|
853
|
+
] });
|
|
854
|
+
}
|
|
855
|
+
function BooleanField({
|
|
856
|
+
label,
|
|
857
|
+
value,
|
|
858
|
+
onChange,
|
|
859
|
+
disabled
|
|
860
|
+
}) {
|
|
861
|
+
return /* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
862
|
+
label,
|
|
863
|
+
/* @__PURE__ */ jsxs(
|
|
864
|
+
"select",
|
|
865
|
+
{
|
|
866
|
+
value: triState(value),
|
|
867
|
+
disabled,
|
|
868
|
+
style: inputStyle,
|
|
869
|
+
onChange: (event) => onChange(booleanFromTriState(event.target.value)),
|
|
870
|
+
children: [
|
|
871
|
+
/* @__PURE__ */ jsx("option", { value: "default", children: "Browser default" }),
|
|
872
|
+
/* @__PURE__ */ jsx("option", { value: "true", children: "On" }),
|
|
873
|
+
/* @__PURE__ */ jsx("option", { value: "false", children: "Off" })
|
|
874
|
+
]
|
|
875
|
+
}
|
|
876
|
+
)
|
|
877
|
+
] });
|
|
878
|
+
}
|
|
879
|
+
function RecorderDeviceSettingsPanel({
|
|
880
|
+
value,
|
|
881
|
+
onChange,
|
|
882
|
+
disabled = false,
|
|
883
|
+
microphoneEnabled,
|
|
884
|
+
cameraEnabled,
|
|
885
|
+
screenEnabled,
|
|
886
|
+
systemAudioEnabled = false,
|
|
887
|
+
separateAudioRecorder = false,
|
|
888
|
+
primaryStream = null,
|
|
889
|
+
cameraStream = null
|
|
890
|
+
}) {
|
|
891
|
+
const [devices, setDevices] = useState2([]);
|
|
892
|
+
const [supported, setSupported] = useState2(null);
|
|
893
|
+
const audioMimeListId = useId();
|
|
894
|
+
const videoMimeListId = useId();
|
|
895
|
+
const refreshBrowserInfo = useCallback2(async () => {
|
|
896
|
+
const mediaDevices = typeof navigator === "undefined" ? void 0 : navigator.mediaDevices;
|
|
897
|
+
if (!mediaDevices) return;
|
|
898
|
+
if (typeof mediaDevices.getSupportedConstraints === "function") {
|
|
899
|
+
setSupported(mediaDevices.getSupportedConstraints());
|
|
900
|
+
}
|
|
901
|
+
if (typeof mediaDevices.enumerateDevices === "function") {
|
|
902
|
+
try {
|
|
903
|
+
setDevices(await mediaDevices.enumerateDevices());
|
|
904
|
+
} catch {
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}, []);
|
|
908
|
+
useEffect2(() => {
|
|
909
|
+
void refreshBrowserInfo();
|
|
910
|
+
const mediaDevices = typeof navigator === "undefined" ? void 0 : navigator.mediaDevices;
|
|
911
|
+
if (!mediaDevices?.addEventListener) return;
|
|
912
|
+
const handleDeviceChange = () => void refreshBrowserInfo();
|
|
913
|
+
mediaDevices.addEventListener("devicechange", handleDeviceChange);
|
|
914
|
+
return () => mediaDevices.removeEventListener("devicechange", handleDeviceChange);
|
|
915
|
+
}, [refreshBrowserInfo]);
|
|
916
|
+
useEffect2(() => {
|
|
917
|
+
if (primaryStream || cameraStream) void refreshBrowserInfo();
|
|
918
|
+
}, [cameraStream, primaryStream, refreshBrowserInfo]);
|
|
919
|
+
const supports = (key) => supported === null || supported[key] === true;
|
|
920
|
+
const hasAudioTrack = microphoneEnabled || systemAudioEnabled;
|
|
921
|
+
const hasStandaloneAudioRecorder = separateAudioRecorder || microphoneEnabled && !cameraEnabled && !screenEnabled;
|
|
922
|
+
const audioDevices = devices.filter((device) => device.kind === "audioinput");
|
|
923
|
+
const videoDevices = devices.filter((device) => device.kind === "videoinput");
|
|
924
|
+
const audioGroups = deviceGroups(audioDevices);
|
|
925
|
+
const videoGroups = deviceGroups(videoDevices);
|
|
926
|
+
const patchAudio = (patch) => onChange({ ...value, audio: { ...value.audio, ...patch } });
|
|
927
|
+
const patchCamera = (patch) => onChange({ ...value, camera: { ...value.camera, ...patch } });
|
|
928
|
+
const patchScreen = (patch) => onChange({ ...value, screen: { ...value.screen, ...patch } });
|
|
929
|
+
const patchScreenAudio = (patch) => onChange({ ...value, screenAudio: { ...value.screenAudio, ...patch } });
|
|
930
|
+
const patchEncoding = (patch) => onChange({ ...value, encoding: { ...value.encoding, ...patch } });
|
|
931
|
+
const primaryAudioSettings = readSettings(primaryStream?.getAudioTracks()[0]);
|
|
932
|
+
const primaryVideoSettings = readSettings(primaryStream?.getVideoTracks()[0]);
|
|
933
|
+
const secondaryVideoSettings = readSettings(cameraStream?.getVideoTracks()[0]);
|
|
934
|
+
const actualSettings = {
|
|
935
|
+
...primaryAudioSettings ? { audio: primaryAudioSettings } : {},
|
|
936
|
+
...primaryVideoSettings ? { [screenEnabled ? "screen" : "camera"]: primaryVideoSettings } : {},
|
|
937
|
+
...secondaryVideoSettings ? { camera: secondaryVideoSettings } : {}
|
|
938
|
+
};
|
|
939
|
+
return /* @__PURE__ */ jsxs("details", { style: detailsStyle, "data-testid": "recorder-device-settings", children: [
|
|
940
|
+
/* @__PURE__ */ jsx("summary", { style: summaryToggleStyle, children: "Advanced device settings" }),
|
|
941
|
+
/* @__PURE__ */ jsxs("div", { style: panelStyle, children: [
|
|
942
|
+
/* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
943
|
+
"Constraint strength",
|
|
944
|
+
/* @__PURE__ */ jsxs(
|
|
945
|
+
"select",
|
|
946
|
+
{
|
|
947
|
+
value: value.constraintMode,
|
|
948
|
+
disabled,
|
|
949
|
+
style: inputStyle,
|
|
950
|
+
onChange: (event) => onChange({
|
|
951
|
+
...value,
|
|
952
|
+
constraintMode: event.target.value === "exact" ? "exact" : "ideal"
|
|
953
|
+
}),
|
|
954
|
+
children: [
|
|
955
|
+
/* @__PURE__ */ jsx("option", { value: "ideal", children: "Preferred (use closest available)" }),
|
|
956
|
+
/* @__PURE__ */ jsx("option", { value: "exact", children: "Required (fail when unavailable)" })
|
|
957
|
+
]
|
|
958
|
+
}
|
|
959
|
+
)
|
|
960
|
+
] }),
|
|
961
|
+
microphoneEnabled && /* @__PURE__ */ jsxs("fieldset", { style: fieldsetStyle, disabled, children: [
|
|
962
|
+
/* @__PURE__ */ jsx("legend", { style: legendStyle, children: "Microphone" }),
|
|
963
|
+
/* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
|
|
964
|
+
/* @__PURE__ */ jsxs("label", { style: { ...fieldStyle, gridColumn: "1 / -1" }, children: [
|
|
965
|
+
"Input device",
|
|
966
|
+
/* @__PURE__ */ jsxs(
|
|
967
|
+
"select",
|
|
968
|
+
{
|
|
969
|
+
"aria-label": "Recording microphone",
|
|
970
|
+
value: value.audio.deviceId,
|
|
971
|
+
style: inputStyle,
|
|
972
|
+
onChange: (event) => patchAudio({ deviceId: event.target.value }),
|
|
973
|
+
children: [
|
|
974
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "System default" }),
|
|
975
|
+
audioDevices.map((device, index) => /* @__PURE__ */ jsx("option", { value: device.deviceId, children: deviceLabel(device, index, "Microphone") }, device.deviceId))
|
|
976
|
+
]
|
|
977
|
+
}
|
|
978
|
+
)
|
|
979
|
+
] }),
|
|
980
|
+
supports("groupId") && audioGroups.length > 0 && /* @__PURE__ */ jsxs("label", { style: { ...fieldStyle, gridColumn: "1 / -1" }, children: [
|
|
981
|
+
"Device group",
|
|
982
|
+
/* @__PURE__ */ jsxs(
|
|
983
|
+
"select",
|
|
984
|
+
{
|
|
985
|
+
value: value.audio.groupId ?? "",
|
|
986
|
+
style: inputStyle,
|
|
987
|
+
onChange: (event) => patchAudio({ groupId: event.target.value || void 0 }),
|
|
988
|
+
children: [
|
|
989
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Any group" }),
|
|
990
|
+
audioGroups.map((group) => /* @__PURE__ */ jsx("option", { value: group.id, children: group.label }, group.id))
|
|
991
|
+
]
|
|
992
|
+
}
|
|
993
|
+
)
|
|
994
|
+
] }),
|
|
995
|
+
supports("sampleRate") && /* @__PURE__ */ jsx(
|
|
996
|
+
NumericField,
|
|
997
|
+
{
|
|
998
|
+
label: "Sample rate (Hz)",
|
|
999
|
+
value: value.audio.sampleRate,
|
|
1000
|
+
onChange: (sampleRate) => patchAudio({ sampleRate }),
|
|
1001
|
+
disabled
|
|
1002
|
+
}
|
|
1003
|
+
),
|
|
1004
|
+
supports("sampleSize") && /* @__PURE__ */ jsx(
|
|
1005
|
+
NumericField,
|
|
1006
|
+
{
|
|
1007
|
+
label: "Sample size (bits)",
|
|
1008
|
+
value: value.audio.sampleSize,
|
|
1009
|
+
onChange: (sampleSize) => patchAudio({ sampleSize }),
|
|
1010
|
+
disabled
|
|
1011
|
+
}
|
|
1012
|
+
),
|
|
1013
|
+
supports("channelCount") && /* @__PURE__ */ jsx(
|
|
1014
|
+
NumericField,
|
|
1015
|
+
{
|
|
1016
|
+
label: "Channel count",
|
|
1017
|
+
value: value.audio.channelCount,
|
|
1018
|
+
onChange: (channelCount) => patchAudio({ channelCount }),
|
|
1019
|
+
disabled
|
|
1020
|
+
}
|
|
1021
|
+
),
|
|
1022
|
+
supports("latency") && /* @__PURE__ */ jsx(
|
|
1023
|
+
NumericField,
|
|
1024
|
+
{
|
|
1025
|
+
label: "Latency (seconds)",
|
|
1026
|
+
value: value.audio.latency,
|
|
1027
|
+
onChange: (latency) => patchAudio({ latency }),
|
|
1028
|
+
disabled,
|
|
1029
|
+
step: 1e-3
|
|
1030
|
+
}
|
|
1031
|
+
),
|
|
1032
|
+
supports("echoCancellation") && /* @__PURE__ */ jsx(
|
|
1033
|
+
BooleanField,
|
|
1034
|
+
{
|
|
1035
|
+
label: "Echo cancellation",
|
|
1036
|
+
value: value.audio.echoCancellation,
|
|
1037
|
+
onChange: (echoCancellation) => patchAudio({ echoCancellation }),
|
|
1038
|
+
disabled
|
|
1039
|
+
}
|
|
1040
|
+
),
|
|
1041
|
+
supports("noiseSuppression") && /* @__PURE__ */ jsx(
|
|
1042
|
+
BooleanField,
|
|
1043
|
+
{
|
|
1044
|
+
label: "Noise suppression",
|
|
1045
|
+
value: value.audio.noiseSuppression,
|
|
1046
|
+
onChange: (noiseSuppression) => patchAudio({ noiseSuppression }),
|
|
1047
|
+
disabled
|
|
1048
|
+
}
|
|
1049
|
+
),
|
|
1050
|
+
supports("autoGainControl") && /* @__PURE__ */ jsx(
|
|
1051
|
+
BooleanField,
|
|
1052
|
+
{
|
|
1053
|
+
label: "Automatic gain control",
|
|
1054
|
+
value: value.audio.autoGainControl,
|
|
1055
|
+
onChange: (autoGainControl) => patchAudio({ autoGainControl }),
|
|
1056
|
+
disabled
|
|
1057
|
+
}
|
|
1058
|
+
)
|
|
1059
|
+
] })
|
|
1060
|
+
] }),
|
|
1061
|
+
cameraEnabled && /* @__PURE__ */ jsxs("fieldset", { style: fieldsetStyle, disabled, children: [
|
|
1062
|
+
/* @__PURE__ */ jsx("legend", { style: legendStyle, children: "Camera" }),
|
|
1063
|
+
/* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
|
|
1064
|
+
/* @__PURE__ */ jsxs("label", { style: { ...fieldStyle, gridColumn: "1 / -1" }, children: [
|
|
1065
|
+
"Video input",
|
|
1066
|
+
/* @__PURE__ */ jsxs(
|
|
1067
|
+
"select",
|
|
1068
|
+
{
|
|
1069
|
+
"aria-label": "Recording camera",
|
|
1070
|
+
value: value.camera.deviceId,
|
|
1071
|
+
style: inputStyle,
|
|
1072
|
+
onChange: (event) => patchCamera({ deviceId: event.target.value }),
|
|
1073
|
+
children: [
|
|
1074
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "System default" }),
|
|
1075
|
+
videoDevices.map((device, index) => /* @__PURE__ */ jsx("option", { value: device.deviceId, children: deviceLabel(device, index, "Camera") }, device.deviceId))
|
|
1076
|
+
]
|
|
1077
|
+
}
|
|
1078
|
+
)
|
|
1079
|
+
] }),
|
|
1080
|
+
supports("groupId") && videoGroups.length > 0 && /* @__PURE__ */ jsxs("label", { style: { ...fieldStyle, gridColumn: "1 / -1" }, children: [
|
|
1081
|
+
"Device group",
|
|
1082
|
+
/* @__PURE__ */ jsxs(
|
|
1083
|
+
"select",
|
|
1084
|
+
{
|
|
1085
|
+
value: value.camera.groupId ?? "",
|
|
1086
|
+
style: inputStyle,
|
|
1087
|
+
onChange: (event) => patchCamera({ groupId: event.target.value || void 0 }),
|
|
1088
|
+
children: [
|
|
1089
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Any group" }),
|
|
1090
|
+
videoGroups.map((group) => /* @__PURE__ */ jsx("option", { value: group.id, children: group.label }, group.id))
|
|
1091
|
+
]
|
|
1092
|
+
}
|
|
1093
|
+
)
|
|
1094
|
+
] }),
|
|
1095
|
+
supports("width") && /* @__PURE__ */ jsx(
|
|
1096
|
+
NumericField,
|
|
1097
|
+
{
|
|
1098
|
+
label: "Width (px)",
|
|
1099
|
+
value: value.camera.width,
|
|
1100
|
+
onChange: (width) => patchCamera({ width }),
|
|
1101
|
+
disabled
|
|
1102
|
+
}
|
|
1103
|
+
),
|
|
1104
|
+
supports("height") && /* @__PURE__ */ jsx(
|
|
1105
|
+
NumericField,
|
|
1106
|
+
{
|
|
1107
|
+
label: "Height (px)",
|
|
1108
|
+
value: value.camera.height,
|
|
1109
|
+
onChange: (height) => patchCamera({ height }),
|
|
1110
|
+
disabled
|
|
1111
|
+
}
|
|
1112
|
+
),
|
|
1113
|
+
supports("aspectRatio") && /* @__PURE__ */ jsx(
|
|
1114
|
+
NumericField,
|
|
1115
|
+
{
|
|
1116
|
+
label: "Aspect ratio (width / height)",
|
|
1117
|
+
value: value.camera.aspectRatio,
|
|
1118
|
+
onChange: (aspectRatio) => patchCamera({ aspectRatio }),
|
|
1119
|
+
disabled,
|
|
1120
|
+
step: 0.01
|
|
1121
|
+
}
|
|
1122
|
+
),
|
|
1123
|
+
supports("frameRate") && /* @__PURE__ */ jsx(
|
|
1124
|
+
NumericField,
|
|
1125
|
+
{
|
|
1126
|
+
label: "Frame rate (fps)",
|
|
1127
|
+
value: value.camera.frameRate,
|
|
1128
|
+
onChange: (frameRate) => patchCamera({ frameRate }),
|
|
1129
|
+
disabled,
|
|
1130
|
+
step: 0.01
|
|
1131
|
+
}
|
|
1132
|
+
),
|
|
1133
|
+
supports("facingMode") && /* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
1134
|
+
"Facing mode",
|
|
1135
|
+
/* @__PURE__ */ jsxs(
|
|
1136
|
+
"select",
|
|
1137
|
+
{
|
|
1138
|
+
value: value.camera.facingMode ?? "",
|
|
1139
|
+
disabled,
|
|
1140
|
+
style: inputStyle,
|
|
1141
|
+
onChange: (event) => patchCamera({ facingMode: event.target.value || void 0 }),
|
|
1142
|
+
children: [
|
|
1143
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Browser default" }),
|
|
1144
|
+
/* @__PURE__ */ jsx("option", { value: "user", children: "User/front" }),
|
|
1145
|
+
/* @__PURE__ */ jsx("option", { value: "environment", children: "Environment/rear" }),
|
|
1146
|
+
/* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
|
|
1147
|
+
/* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
|
|
1148
|
+
]
|
|
1149
|
+
}
|
|
1150
|
+
)
|
|
1151
|
+
] }),
|
|
1152
|
+
supports("resizeMode") && /* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
1153
|
+
"Resize mode",
|
|
1154
|
+
/* @__PURE__ */ jsxs(
|
|
1155
|
+
"select",
|
|
1156
|
+
{
|
|
1157
|
+
value: value.camera.resizeMode ?? "",
|
|
1158
|
+
disabled,
|
|
1159
|
+
style: inputStyle,
|
|
1160
|
+
onChange: (event) => patchCamera({ resizeMode: event.target.value || void 0 }),
|
|
1161
|
+
children: [
|
|
1162
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Browser default" }),
|
|
1163
|
+
/* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
|
|
1164
|
+
/* @__PURE__ */ jsx("option", { value: "crop-and-scale", children: "Crop and scale" })
|
|
1165
|
+
]
|
|
1166
|
+
}
|
|
1167
|
+
)
|
|
1168
|
+
] }),
|
|
1169
|
+
supports("backgroundBlur") && /* @__PURE__ */ jsx(
|
|
1170
|
+
BooleanField,
|
|
1171
|
+
{
|
|
1172
|
+
label: "Background blur",
|
|
1173
|
+
value: value.camera.backgroundBlur,
|
|
1174
|
+
onChange: (backgroundBlur) => patchCamera({ backgroundBlur }),
|
|
1175
|
+
disabled
|
|
1176
|
+
}
|
|
1177
|
+
)
|
|
1178
|
+
] })
|
|
1179
|
+
] }),
|
|
1180
|
+
(screenEnabled || systemAudioEnabled) && /* @__PURE__ */ jsxs("fieldset", { style: fieldsetStyle, disabled, children: [
|
|
1181
|
+
/* @__PURE__ */ jsx("legend", { style: legendStyle, children: screenEnabled ? "Screen capture" : "System audio capture" }),
|
|
1182
|
+
/* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
|
|
1183
|
+
screenEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1184
|
+
supports("displaySurface") && /* @__PURE__ */ jsxs("label", { style: { ...fieldStyle, gridColumn: "1 / -1" }, children: [
|
|
1185
|
+
"Preferred surface",
|
|
1186
|
+
/* @__PURE__ */ jsxs(
|
|
1187
|
+
"select",
|
|
1188
|
+
{
|
|
1189
|
+
value: value.screen.displaySurface ?? "",
|
|
1190
|
+
disabled,
|
|
1191
|
+
style: inputStyle,
|
|
1192
|
+
onChange: (event) => patchScreen({ displaySurface: event.target.value || void 0 }),
|
|
1193
|
+
children: [
|
|
1194
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Browser picker default" }),
|
|
1195
|
+
/* @__PURE__ */ jsx("option", { value: "monitor", children: "Entire monitor" }),
|
|
1196
|
+
/* @__PURE__ */ jsx("option", { value: "window", children: "Application window" }),
|
|
1197
|
+
/* @__PURE__ */ jsx("option", { value: "browser", children: "Browser tab" })
|
|
1198
|
+
]
|
|
1199
|
+
}
|
|
1200
|
+
)
|
|
1201
|
+
] }),
|
|
1202
|
+
supports("cursor") && /* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
1203
|
+
"Mouse cursor",
|
|
1204
|
+
/* @__PURE__ */ jsxs(
|
|
1205
|
+
"select",
|
|
1206
|
+
{
|
|
1207
|
+
value: value.screen.cursor ?? "",
|
|
1208
|
+
disabled,
|
|
1209
|
+
style: inputStyle,
|
|
1210
|
+
onChange: (event) => patchScreen({ cursor: event.target.value || void 0 }),
|
|
1211
|
+
children: [
|
|
1212
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Browser default" }),
|
|
1213
|
+
/* @__PURE__ */ jsx("option", { value: "always", children: "Always" }),
|
|
1214
|
+
/* @__PURE__ */ jsx("option", { value: "motion", children: "While moving" }),
|
|
1215
|
+
/* @__PURE__ */ jsx("option", { value: "never", children: "Never" })
|
|
1216
|
+
]
|
|
1217
|
+
}
|
|
1218
|
+
)
|
|
1219
|
+
] }),
|
|
1220
|
+
supports("logicalSurface") && /* @__PURE__ */ jsx(
|
|
1221
|
+
BooleanField,
|
|
1222
|
+
{
|
|
1223
|
+
label: "Logical surface",
|
|
1224
|
+
value: value.screen.logicalSurface,
|
|
1225
|
+
onChange: (logicalSurface) => patchScreen({ logicalSurface }),
|
|
1226
|
+
disabled
|
|
1227
|
+
}
|
|
1228
|
+
),
|
|
1229
|
+
supports("resizeMode") && /* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
1230
|
+
"Resize mode",
|
|
1231
|
+
/* @__PURE__ */ jsxs(
|
|
1232
|
+
"select",
|
|
1233
|
+
{
|
|
1234
|
+
value: value.screen.resizeMode ?? "",
|
|
1235
|
+
disabled,
|
|
1236
|
+
style: inputStyle,
|
|
1237
|
+
onChange: (event) => patchScreen({ resizeMode: event.target.value || void 0 }),
|
|
1238
|
+
children: [
|
|
1239
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Browser default" }),
|
|
1240
|
+
/* @__PURE__ */ jsx("option", { value: "none", children: "Full detail" }),
|
|
1241
|
+
/* @__PURE__ */ jsx("option", { value: "crop-and-scale", children: "Downscale" })
|
|
1242
|
+
]
|
|
1243
|
+
}
|
|
1244
|
+
)
|
|
1245
|
+
] }),
|
|
1246
|
+
supports("width") && /* @__PURE__ */ jsx(
|
|
1247
|
+
NumericField,
|
|
1248
|
+
{
|
|
1249
|
+
label: "Width (px)",
|
|
1250
|
+
value: value.screen.width,
|
|
1251
|
+
onChange: (width) => patchScreen({ width }),
|
|
1252
|
+
disabled
|
|
1253
|
+
}
|
|
1254
|
+
),
|
|
1255
|
+
supports("height") && /* @__PURE__ */ jsx(
|
|
1256
|
+
NumericField,
|
|
1257
|
+
{
|
|
1258
|
+
label: "Height (px)",
|
|
1259
|
+
value: value.screen.height,
|
|
1260
|
+
onChange: (height) => patchScreen({ height }),
|
|
1261
|
+
disabled
|
|
1262
|
+
}
|
|
1263
|
+
),
|
|
1264
|
+
supports("aspectRatio") && /* @__PURE__ */ jsx(
|
|
1265
|
+
NumericField,
|
|
1266
|
+
{
|
|
1267
|
+
label: "Aspect ratio (width / height)",
|
|
1268
|
+
value: value.screen.aspectRatio,
|
|
1269
|
+
onChange: (aspectRatio) => patchScreen({ aspectRatio }),
|
|
1270
|
+
disabled,
|
|
1271
|
+
step: 0.01
|
|
1272
|
+
}
|
|
1273
|
+
),
|
|
1274
|
+
supports("frameRate") && /* @__PURE__ */ jsx(
|
|
1275
|
+
NumericField,
|
|
1276
|
+
{
|
|
1277
|
+
label: "Frame rate (fps)",
|
|
1278
|
+
value: value.screen.frameRate,
|
|
1279
|
+
onChange: (frameRate) => patchScreen({ frameRate }),
|
|
1280
|
+
disabled,
|
|
1281
|
+
step: 0.01
|
|
1282
|
+
}
|
|
1283
|
+
)
|
|
1284
|
+
] }),
|
|
1285
|
+
systemAudioEnabled && supports("restrictOwnAudio") && /* @__PURE__ */ jsx(
|
|
1286
|
+
BooleanField,
|
|
1287
|
+
{
|
|
1288
|
+
label: "Remove this tab's audio",
|
|
1289
|
+
value: value.screenAudio.restrictOwnAudio,
|
|
1290
|
+
onChange: (restrictOwnAudio) => patchScreenAudio({ restrictOwnAudio }),
|
|
1291
|
+
disabled
|
|
1292
|
+
}
|
|
1293
|
+
),
|
|
1294
|
+
systemAudioEnabled && supports("suppressLocalAudioPlayback") && /* @__PURE__ */ jsx(
|
|
1295
|
+
BooleanField,
|
|
1296
|
+
{
|
|
1297
|
+
label: "Mute captured tab locally",
|
|
1298
|
+
value: value.screenAudio.suppressLocalAudioPlayback,
|
|
1299
|
+
onChange: (suppressLocalAudioPlayback) => patchScreenAudio({ suppressLocalAudioPlayback }),
|
|
1300
|
+
disabled
|
|
1301
|
+
}
|
|
1302
|
+
)
|
|
1303
|
+
] }),
|
|
1304
|
+
/* @__PURE__ */ jsx("p", { style: noteStyle, children: "The browser still shows its own surface picker and may limit which display constraints it honors." })
|
|
1305
|
+
] }),
|
|
1306
|
+
/* @__PURE__ */ jsxs("fieldset", { style: fieldsetStyle, disabled, children: [
|
|
1307
|
+
/* @__PURE__ */ jsx("legend", { style: legendStyle, children: "Encoding" }),
|
|
1308
|
+
/* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
|
|
1309
|
+
hasStandaloneAudioRecorder && /* @__PURE__ */ jsxs("label", { style: { ...fieldStyle, gridColumn: "1 / -1" }, children: [
|
|
1310
|
+
"Audio MIME type / codecs",
|
|
1311
|
+
/* @__PURE__ */ jsx(
|
|
1312
|
+
"input",
|
|
1313
|
+
{
|
|
1314
|
+
type: "text",
|
|
1315
|
+
list: audioMimeListId,
|
|
1316
|
+
value: value.encoding.audioMimeType,
|
|
1317
|
+
style: inputStyle,
|
|
1318
|
+
placeholder: "Automatic",
|
|
1319
|
+
onChange: (event) => patchEncoding({ audioMimeType: event.target.value })
|
|
1320
|
+
}
|
|
1321
|
+
),
|
|
1322
|
+
/* @__PURE__ */ jsx("datalist", { id: audioMimeListId, children: AUDIO_MIME_TYPES.map((mime) => /* @__PURE__ */ jsx("option", { value: mime }, mime)) })
|
|
1323
|
+
] }),
|
|
1324
|
+
hasAudioTrack && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
|
|
1325
|
+
NumericField,
|
|
1326
|
+
{
|
|
1327
|
+
label: "Audio bitrate (kbps)",
|
|
1328
|
+
value: value.encoding.audioBitsPerSecond,
|
|
1329
|
+
onChange: (audioBitsPerSecond) => patchEncoding({ audioBitsPerSecond }),
|
|
1330
|
+
disabled
|
|
1331
|
+
}
|
|
1332
|
+
) }),
|
|
1333
|
+
(cameraEnabled || screenEnabled) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1334
|
+
/* @__PURE__ */ jsxs("label", { style: { ...fieldStyle, gridColumn: "1 / -1" }, children: [
|
|
1335
|
+
"Video MIME type / codecs",
|
|
1336
|
+
/* @__PURE__ */ jsx(
|
|
1337
|
+
"input",
|
|
1338
|
+
{
|
|
1339
|
+
type: "text",
|
|
1340
|
+
list: videoMimeListId,
|
|
1341
|
+
value: value.encoding.videoMimeType,
|
|
1342
|
+
style: inputStyle,
|
|
1343
|
+
placeholder: "Automatic",
|
|
1344
|
+
onChange: (event) => patchEncoding({ videoMimeType: event.target.value })
|
|
1345
|
+
}
|
|
1346
|
+
),
|
|
1347
|
+
/* @__PURE__ */ jsx("datalist", { id: videoMimeListId, children: VIDEO_MIME_TYPES.map((mime) => /* @__PURE__ */ jsx("option", { value: mime }, mime)) })
|
|
1348
|
+
] }),
|
|
1349
|
+
/* @__PURE__ */ jsx(
|
|
1350
|
+
NumericField,
|
|
1351
|
+
{
|
|
1352
|
+
label: "Video bitrate (kbps)",
|
|
1353
|
+
value: value.encoding.videoBitsPerSecond,
|
|
1354
|
+
onChange: (videoBitsPerSecond) => patchEncoding({ videoBitsPerSecond }),
|
|
1355
|
+
disabled
|
|
1356
|
+
}
|
|
1357
|
+
)
|
|
1358
|
+
] }),
|
|
1359
|
+
/* @__PURE__ */ jsx(
|
|
1360
|
+
NumericField,
|
|
1361
|
+
{
|
|
1362
|
+
label: "Total bitrate (kbps)",
|
|
1363
|
+
value: value.encoding.bitsPerSecond,
|
|
1364
|
+
onChange: (bitsPerSecond) => patchEncoding({ bitsPerSecond }),
|
|
1365
|
+
disabled
|
|
1366
|
+
}
|
|
1367
|
+
),
|
|
1368
|
+
hasAudioTrack && /* @__PURE__ */ jsxs("label", { style: fieldStyle, children: [
|
|
1369
|
+
"Audio bitrate mode",
|
|
1370
|
+
/* @__PURE__ */ jsxs(
|
|
1371
|
+
"select",
|
|
1372
|
+
{
|
|
1373
|
+
value: value.encoding.audioBitrateMode ?? "",
|
|
1374
|
+
disabled,
|
|
1375
|
+
style: inputStyle,
|
|
1376
|
+
onChange: (event) => patchEncoding({
|
|
1377
|
+
audioBitrateMode: event.target.value === "constant" || event.target.value === "variable" ? event.target.value : void 0
|
|
1378
|
+
}),
|
|
1379
|
+
children: [
|
|
1380
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Browser default" }),
|
|
1381
|
+
/* @__PURE__ */ jsx("option", { value: "variable", children: "Variable" }),
|
|
1382
|
+
/* @__PURE__ */ jsx("option", { value: "constant", children: "Constant" })
|
|
1383
|
+
]
|
|
1384
|
+
}
|
|
1385
|
+
)
|
|
1386
|
+
] }),
|
|
1387
|
+
(cameraEnabled || screenEnabled) && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1388
|
+
/* @__PURE__ */ jsx(
|
|
1389
|
+
NumericField,
|
|
1390
|
+
{
|
|
1391
|
+
label: "Keyframe interval (ms)",
|
|
1392
|
+
value: value.encoding.videoKeyFrameIntervalDuration,
|
|
1393
|
+
onChange: (videoKeyFrameIntervalDuration) => patchEncoding({
|
|
1394
|
+
videoKeyFrameIntervalDuration,
|
|
1395
|
+
videoKeyFrameIntervalCount: void 0
|
|
1396
|
+
}),
|
|
1397
|
+
disabled
|
|
1398
|
+
}
|
|
1399
|
+
),
|
|
1400
|
+
/* @__PURE__ */ jsx(
|
|
1401
|
+
NumericField,
|
|
1402
|
+
{
|
|
1403
|
+
label: "Keyframe interval (frames)",
|
|
1404
|
+
value: value.encoding.videoKeyFrameIntervalCount,
|
|
1405
|
+
onChange: (videoKeyFrameIntervalCount) => patchEncoding({
|
|
1406
|
+
videoKeyFrameIntervalCount,
|
|
1407
|
+
videoKeyFrameIntervalDuration: void 0
|
|
1408
|
+
}),
|
|
1409
|
+
disabled
|
|
1410
|
+
}
|
|
1411
|
+
)
|
|
1412
|
+
] })
|
|
1413
|
+
] }),
|
|
1414
|
+
/* @__PURE__ */ jsx("p", { style: noteStyle, children: "MIME and bitrate values are hints. Unsupported MIME choices fall back to the recorder's automatic format selection. A total bitrate overrides separate audio/video bitrate hints." })
|
|
1415
|
+
] }),
|
|
1416
|
+
Object.keys(actualSettings).length > 0 && /* @__PURE__ */ jsxs("fieldset", { style: fieldsetStyle, children: [
|
|
1417
|
+
/* @__PURE__ */ jsx("legend", { style: legendStyle, children: "Active track settings" }),
|
|
1418
|
+
/* @__PURE__ */ jsx("pre", { style: actualStyle, children: JSON.stringify(actualSettings, null, 2) })
|
|
1419
|
+
] }),
|
|
1420
|
+
/* @__PURE__ */ jsx("p", { style: noteStyle, children: "Only constraints advertised by this browser are shown. Device names may appear only after microphone or camera permission is granted." })
|
|
1421
|
+
] })
|
|
1422
|
+
] });
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// src/recorder/deviceSettings.ts
|
|
1426
|
+
var DEFAULT_RECORDER_DEVICE_SETTINGS = {
|
|
1427
|
+
constraintMode: "ideal",
|
|
1428
|
+
audio: { deviceId: "" },
|
|
1429
|
+
camera: { deviceId: "" },
|
|
1430
|
+
screen: {},
|
|
1431
|
+
screenAudio: {},
|
|
1432
|
+
encoding: {
|
|
1433
|
+
audioMimeType: "",
|
|
1434
|
+
videoMimeType: ""
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
function preferredNumber(value, mode) {
|
|
1438
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) return void 0;
|
|
1439
|
+
return { [mode]: value };
|
|
1440
|
+
}
|
|
1441
|
+
function preferredInteger(value, mode) {
|
|
1442
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) return void 0;
|
|
1443
|
+
return { [mode]: Math.round(value) };
|
|
1444
|
+
}
|
|
1445
|
+
function preferredString(value, mode) {
|
|
1446
|
+
const trimmed = value?.trim();
|
|
1447
|
+
return trimmed ? { [mode]: trimmed } : void 0;
|
|
1448
|
+
}
|
|
1449
|
+
function buildRecorderAudioConstraints(settings) {
|
|
1450
|
+
const { audio, constraintMode } = settings;
|
|
1451
|
+
const result = {};
|
|
1452
|
+
if (audio.deviceId) result.deviceId = { exact: audio.deviceId };
|
|
1453
|
+
const groupId = preferredString(audio.groupId, constraintMode);
|
|
1454
|
+
if (groupId) result.groupId = groupId;
|
|
1455
|
+
if (audio.autoGainControl !== void 0) result.autoGainControl = audio.autoGainControl;
|
|
1456
|
+
if (audio.echoCancellation !== void 0) result.echoCancellation = audio.echoCancellation;
|
|
1457
|
+
if (audio.noiseSuppression !== void 0) result.noiseSuppression = audio.noiseSuppression;
|
|
1458
|
+
const channelCount = preferredInteger(audio.channelCount, constraintMode);
|
|
1459
|
+
const latency = preferredNumber(audio.latency, constraintMode);
|
|
1460
|
+
const sampleRate = preferredInteger(audio.sampleRate, constraintMode);
|
|
1461
|
+
const sampleSize = preferredInteger(audio.sampleSize, constraintMode);
|
|
1462
|
+
if (channelCount) result.channelCount = channelCount;
|
|
1463
|
+
if (latency) result.latency = latency;
|
|
1464
|
+
if (sampleRate) result.sampleRate = sampleRate;
|
|
1465
|
+
if (sampleSize) result.sampleSize = sampleSize;
|
|
1466
|
+
return result;
|
|
1467
|
+
}
|
|
1468
|
+
function buildRecorderCameraConstraints(settings) {
|
|
1469
|
+
const { camera, constraintMode } = settings;
|
|
1470
|
+
const result = {};
|
|
1471
|
+
if (camera.deviceId) result.deviceId = { exact: camera.deviceId };
|
|
1472
|
+
const groupId = preferredString(camera.groupId, constraintMode);
|
|
1473
|
+
if (groupId) result.groupId = groupId;
|
|
1474
|
+
if (camera.backgroundBlur !== void 0) result.backgroundBlur = camera.backgroundBlur;
|
|
1475
|
+
const aspectRatio = preferredNumber(camera.aspectRatio, constraintMode);
|
|
1476
|
+
const facingMode = preferredString(camera.facingMode, constraintMode);
|
|
1477
|
+
const frameRate = preferredNumber(camera.frameRate, constraintMode);
|
|
1478
|
+
const height = preferredInteger(camera.height, constraintMode);
|
|
1479
|
+
const resizeMode = preferredString(camera.resizeMode, constraintMode);
|
|
1480
|
+
const width = preferredInteger(camera.width, constraintMode);
|
|
1481
|
+
if (aspectRatio) result.aspectRatio = aspectRatio;
|
|
1482
|
+
if (facingMode) result.facingMode = facingMode;
|
|
1483
|
+
if (frameRate) result.frameRate = frameRate;
|
|
1484
|
+
if (height) result.height = height;
|
|
1485
|
+
if (resizeMode) result.resizeMode = resizeMode;
|
|
1486
|
+
if (width) result.width = width;
|
|
1487
|
+
return result;
|
|
1488
|
+
}
|
|
1489
|
+
function buildRecorderScreenConstraints(settings) {
|
|
1490
|
+
const { screen } = settings;
|
|
1491
|
+
const result = {};
|
|
1492
|
+
const aspectRatio = preferredNumber(screen.aspectRatio, "ideal");
|
|
1493
|
+
const cursor = preferredString(screen.cursor, "ideal");
|
|
1494
|
+
const displaySurface = preferredString(screen.displaySurface, "ideal");
|
|
1495
|
+
const frameRate = preferredNumber(screen.frameRate, "ideal");
|
|
1496
|
+
const height = preferredInteger(screen.height, "ideal");
|
|
1497
|
+
const resizeMode = preferredString(screen.resizeMode, "ideal");
|
|
1498
|
+
const width = preferredInteger(screen.width, "ideal");
|
|
1499
|
+
if (screen.logicalSurface !== void 0) result.logicalSurface = screen.logicalSurface;
|
|
1500
|
+
if (aspectRatio) result.aspectRatio = aspectRatio;
|
|
1501
|
+
if (cursor) result.cursor = cursor;
|
|
1502
|
+
if (displaySurface) result.displaySurface = displaySurface;
|
|
1503
|
+
if (frameRate) result.frameRate = frameRate;
|
|
1504
|
+
if (height) result.height = height;
|
|
1505
|
+
if (resizeMode) result.resizeMode = resizeMode;
|
|
1506
|
+
if (width) result.width = width;
|
|
1507
|
+
return result;
|
|
1508
|
+
}
|
|
1509
|
+
function buildRecorderScreenAudioConstraints(settings) {
|
|
1510
|
+
const result = {};
|
|
1511
|
+
if (settings.screenAudio.restrictOwnAudio !== void 0) {
|
|
1512
|
+
result.restrictOwnAudio = settings.screenAudio.restrictOwnAudio;
|
|
1513
|
+
}
|
|
1514
|
+
if (settings.screenAudio.suppressLocalAudioPlayback !== void 0) {
|
|
1515
|
+
result.suppressLocalAudioPlayback = settings.screenAudio.suppressLocalAudioPlayback;
|
|
1516
|
+
}
|
|
1517
|
+
return result;
|
|
1518
|
+
}
|
|
1519
|
+
function recorderBitsPerSecond(value) {
|
|
1520
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) return void 0;
|
|
1521
|
+
return Math.round(value * 1e3);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
702
1524
|
// src/recorder/RecorderModal.tsx
|
|
703
1525
|
import {
|
|
704
|
-
Fragment,
|
|
705
|
-
useCallback as
|
|
706
|
-
useEffect as
|
|
707
|
-
useId,
|
|
1526
|
+
Fragment as Fragment2,
|
|
1527
|
+
useCallback as useCallback3,
|
|
1528
|
+
useEffect as useEffect3,
|
|
1529
|
+
useId as useId2,
|
|
1530
|
+
useMemo,
|
|
708
1531
|
useRef as useRef2,
|
|
709
|
-
useState as
|
|
1532
|
+
useState as useState3
|
|
710
1533
|
} from "react";
|
|
711
1534
|
|
|
712
1535
|
// src/modal/useModalDialog.ts
|
|
@@ -735,7 +1558,7 @@ function narrationCaptureSummary(withCamera) {
|
|
|
735
1558
|
}
|
|
736
1559
|
|
|
737
1560
|
// src/recorder/RecorderModal.tsx
|
|
738
|
-
import { Fragment as
|
|
1561
|
+
import { Fragment as Fragment3, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
739
1562
|
var overlayStyle = {
|
|
740
1563
|
position: "fixed",
|
|
741
1564
|
inset: 0,
|
|
@@ -750,6 +1573,7 @@ function recorderThemeStyle(colorScheme) {
|
|
|
750
1573
|
return {
|
|
751
1574
|
colorScheme,
|
|
752
1575
|
"--squisq-recorder-surface": `var(--squisq-bg, ${dark ? "#1f2937" : "#fffdf7"})`,
|
|
1576
|
+
"--squisq-recorder-surface-muted": `var(--squisq-panel-bg, ${dark ? "#111827" : "#f8f4e8"})`,
|
|
753
1577
|
"--squisq-recorder-input": `var(--squisq-input-bg, ${dark ? "#374151" : "#fff"})`,
|
|
754
1578
|
"--squisq-recorder-border": `var(--squisq-border, ${dark ? "#4b5563" : "#c9b98a"})`,
|
|
755
1579
|
"--squisq-recorder-text": `var(--squisq-text, ${dark ? "#e5e7eb" : "#4a3c1f"})`,
|
|
@@ -788,7 +1612,7 @@ var labelStyle = {
|
|
|
788
1612
|
marginBottom: 4,
|
|
789
1613
|
color: "var(--squisq-recorder-text)"
|
|
790
1614
|
};
|
|
791
|
-
var
|
|
1615
|
+
var inputStyle2 = {
|
|
792
1616
|
width: "100%",
|
|
793
1617
|
padding: "6px 8px",
|
|
794
1618
|
fontSize: 13,
|
|
@@ -801,7 +1625,7 @@ var inputStyle = {
|
|
|
801
1625
|
boxSizing: "border-box"
|
|
802
1626
|
};
|
|
803
1627
|
var textareaStyle = {
|
|
804
|
-
...
|
|
1628
|
+
...inputStyle2,
|
|
805
1629
|
resize: "vertical",
|
|
806
1630
|
minHeight: 72
|
|
807
1631
|
};
|
|
@@ -1082,23 +1906,31 @@ function RecorderModal({
|
|
|
1082
1906
|
narration = null
|
|
1083
1907
|
}) {
|
|
1084
1908
|
const initialToggles = toggleStateFromMode(initialMode);
|
|
1085
|
-
const [micOn, setMicOn] =
|
|
1086
|
-
const [cameraOn, setCameraOn] =
|
|
1087
|
-
const [screenOn, setScreenOn] =
|
|
1088
|
-
const [sourceText, setSourceText] =
|
|
1089
|
-
const [basename, setBasename] =
|
|
1090
|
-
const [includeSystemAudio, setIncludeSystemAudio] =
|
|
1091
|
-
const [isSaving, setIsSaving] =
|
|
1092
|
-
const [saveError, setSaveError] =
|
|
1093
|
-
const [playbackUrl, setPlaybackUrl] =
|
|
1094
|
-
const [cameraPlaybackUrl, setCameraPlaybackUrl] =
|
|
1095
|
-
const [playbackPositionMs, setPlaybackPositionMs] =
|
|
1096
|
-
const [narrationOn, setNarrationOn] =
|
|
1097
|
-
const [narrationRequesting, setNarrationRequesting] =
|
|
1098
|
-
const [narrationPreview, setNarrationPreview] =
|
|
1909
|
+
const [micOn, setMicOn] = useState3(initialToggles.micOn);
|
|
1910
|
+
const [cameraOn, setCameraOn] = useState3(initialToggles.cameraOn);
|
|
1911
|
+
const [screenOn, setScreenOn] = useState3(initialToggles.screenOn);
|
|
1912
|
+
const [sourceText, setSourceText] = useState3("");
|
|
1913
|
+
const [basename, setBasename] = useState3("");
|
|
1914
|
+
const [includeSystemAudio, setIncludeSystemAudio] = useState3(false);
|
|
1915
|
+
const [isSaving, setIsSaving] = useState3(false);
|
|
1916
|
+
const [saveError, setSaveError] = useState3(null);
|
|
1917
|
+
const [playbackUrl, setPlaybackUrl] = useState3(null);
|
|
1918
|
+
const [cameraPlaybackUrl, setCameraPlaybackUrl] = useState3(null);
|
|
1919
|
+
const [playbackPositionMs, setPlaybackPositionMs] = useState3(0);
|
|
1920
|
+
const [narrationOn, setNarrationOn] = useState3(false);
|
|
1921
|
+
const [narrationRequesting, setNarrationRequesting] = useState3(false);
|
|
1922
|
+
const [narrationPreview, setNarrationPreview] = useState3(null);
|
|
1923
|
+
const [deviceSettings, setDeviceSettings] = useState3(() => ({
|
|
1924
|
+
...DEFAULT_RECORDER_DEVICE_SETTINGS,
|
|
1925
|
+
audio: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.audio },
|
|
1926
|
+
camera: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.camera },
|
|
1927
|
+
screen: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.screen },
|
|
1928
|
+
screenAudio: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.screenAudio },
|
|
1929
|
+
encoding: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.encoding }
|
|
1930
|
+
}));
|
|
1099
1931
|
const overlayRef = useRef2(null);
|
|
1100
1932
|
const dialogRef = useRef2(null);
|
|
1101
|
-
const headingId =
|
|
1933
|
+
const headingId = useId2();
|
|
1102
1934
|
const previewRef = useRef2(null);
|
|
1103
1935
|
const cameraPreviewRef = useRef2(null);
|
|
1104
1936
|
const derivedSource = deriveSource({ micOn, cameraOn, screenOn });
|
|
@@ -1106,9 +1938,37 @@ function RecorderModal({
|
|
|
1106
1938
|
const source = derivedSource ?? "mic";
|
|
1107
1939
|
const isDual = source === "screen+camera";
|
|
1108
1940
|
const canIncludeSystemAudio = supportsSystemAudioCapture();
|
|
1941
|
+
const audioConstraints = useMemo(
|
|
1942
|
+
() => buildRecorderAudioConstraints(deviceSettings),
|
|
1943
|
+
[deviceSettings]
|
|
1944
|
+
);
|
|
1945
|
+
const cameraConstraints = useMemo(
|
|
1946
|
+
() => buildRecorderCameraConstraints(deviceSettings),
|
|
1947
|
+
[deviceSettings]
|
|
1948
|
+
);
|
|
1949
|
+
const screenConstraints = useMemo(
|
|
1950
|
+
() => buildRecorderScreenConstraints(deviceSettings),
|
|
1951
|
+
[deviceSettings]
|
|
1952
|
+
);
|
|
1953
|
+
const screenAudioConstraints = useMemo(
|
|
1954
|
+
() => buildRecorderScreenAudioConstraints(deviceSettings),
|
|
1955
|
+
[deviceSettings]
|
|
1956
|
+
);
|
|
1957
|
+
const encoding = deviceSettings.encoding;
|
|
1109
1958
|
const recorder = useMediaRecorder({
|
|
1110
1959
|
source,
|
|
1111
1960
|
includeMicrophone: cameraOn ? micOn : void 0,
|
|
1961
|
+
audioConstraints,
|
|
1962
|
+
videoConstraints: cameraConstraints,
|
|
1963
|
+
screenVideoConstraints: screenConstraints,
|
|
1964
|
+
screenAudioConstraints,
|
|
1965
|
+
mimeType: (source === "mic" ? encoding.audioMimeType : encoding.videoMimeType).trim() || void 0,
|
|
1966
|
+
bitsPerSecond: recorderBitsPerSecond(encoding.bitsPerSecond),
|
|
1967
|
+
audioBitsPerSecond: recorderBitsPerSecond(encoding.audioBitsPerSecond),
|
|
1968
|
+
videoBitsPerSecond: recorderBitsPerSecond(encoding.videoBitsPerSecond),
|
|
1969
|
+
audioBitrateMode: encoding.audioBitrateMode,
|
|
1970
|
+
videoKeyFrameIntervalDuration: encoding.videoKeyFrameIntervalDuration,
|
|
1971
|
+
videoKeyFrameIntervalCount: encoding.videoKeyFrameIntervalCount,
|
|
1112
1972
|
// System audio rides the screen capture when Screen is on, and is otherwise
|
|
1113
1973
|
// captured via a separate (video-discarded) display capture mixed into the
|
|
1114
1974
|
// mic/camera file — so it is no longer gated on Screen.
|
|
@@ -1121,12 +1981,48 @@ function RecorderModal({
|
|
|
1121
1981
|
const stage = useNarrationStage({
|
|
1122
1982
|
doc: narration?.doc ?? null,
|
|
1123
1983
|
recording: narration?.recording ?? null,
|
|
1124
|
-
getAudioBasename: () => basenameRef.current.trim() || void 0
|
|
1984
|
+
getAudioBasename: () => basenameRef.current.trim() || void 0,
|
|
1985
|
+
micConstraints: audioConstraints,
|
|
1986
|
+
cameraConstraints,
|
|
1987
|
+
audioRecorderOptions: {
|
|
1988
|
+
mimeType: encoding.audioMimeType.trim() || void 0,
|
|
1989
|
+
bitsPerSecond: recorderBitsPerSecond(encoding.bitsPerSecond),
|
|
1990
|
+
audioBitsPerSecond: recorderBitsPerSecond(encoding.audioBitsPerSecond),
|
|
1991
|
+
audioBitrateMode: encoding.audioBitrateMode
|
|
1992
|
+
},
|
|
1993
|
+
cameraRecorderOptions: {
|
|
1994
|
+
mimeType: encoding.videoMimeType.trim() || void 0,
|
|
1995
|
+
bitsPerSecond: recorderBitsPerSecond(encoding.bitsPerSecond),
|
|
1996
|
+
videoBitsPerSecond: recorderBitsPerSecond(encoding.videoBitsPerSecond),
|
|
1997
|
+
videoKeyFrameIntervalDuration: encoding.videoKeyFrameIntervalDuration,
|
|
1998
|
+
videoKeyFrameIntervalCount: encoding.videoKeyFrameIntervalCount
|
|
1999
|
+
}
|
|
1125
2000
|
});
|
|
1126
2001
|
const stageRef = useRef2(stage);
|
|
1127
2002
|
stageRef.current = stage;
|
|
2003
|
+
const handleDeviceSettingsChange = useCallback3(
|
|
2004
|
+
(next) => {
|
|
2005
|
+
setDeviceSettings(next);
|
|
2006
|
+
if (narrationOn) {
|
|
2007
|
+
stageRef.current.controller.setPrefs({
|
|
2008
|
+
micDeviceId: next.audio.deviceId || null
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
},
|
|
2012
|
+
[narrationOn]
|
|
2013
|
+
);
|
|
2014
|
+
const narrationMicDeviceId = stage.controller.prefs.micDeviceId ?? "";
|
|
2015
|
+
useEffect3(() => {
|
|
2016
|
+
if (!narrationOn) return;
|
|
2017
|
+
setDeviceSettings(
|
|
2018
|
+
(current) => current.audio.deviceId === narrationMicDeviceId ? current : {
|
|
2019
|
+
...current,
|
|
2020
|
+
audio: { ...current.audio, deviceId: narrationMicDeviceId }
|
|
2021
|
+
}
|
|
2022
|
+
);
|
|
2023
|
+
}, [narrationMicDeviceId, narrationOn]);
|
|
1128
2024
|
const prevNarrationOnRef = useRef2(narrationOn);
|
|
1129
|
-
|
|
2025
|
+
useEffect3(() => {
|
|
1130
2026
|
const was = prevNarrationOnRef.current;
|
|
1131
2027
|
prevNarrationOnRef.current = narrationOn;
|
|
1132
2028
|
if (was === narrationOn) return;
|
|
@@ -1141,7 +2037,7 @@ function RecorderModal({
|
|
|
1141
2037
|
if (s.float.isOpen) s.float.close();
|
|
1142
2038
|
}
|
|
1143
2039
|
}, [narrationOn, recorder]);
|
|
1144
|
-
|
|
2040
|
+
useEffect3(() => {
|
|
1145
2041
|
if (!narrationOn) return;
|
|
1146
2042
|
const onKey = (event) => {
|
|
1147
2043
|
if (event.key !== "Escape") return;
|
|
@@ -1154,21 +2050,23 @@ function RecorderModal({
|
|
|
1154
2050
|
const narrationMicLive = stage.controller.mic.status === "live";
|
|
1155
2051
|
const narrationPreviewWanted = narrationOn && stage.recorder.withCamera && narrationMicLive && stage.recorder.cameraStream === null && stage.recorder.state !== "processing" && stage.recorder.state !== "review" && stage.recorder.state !== "saving";
|
|
1156
2052
|
const narrationPreviewRef = useRef2(null);
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
setNarrationPreview(null);
|
|
1164
|
-
}
|
|
1165
|
-
return;
|
|
2053
|
+
useEffect3(() => {
|
|
2054
|
+
const existing = narrationPreviewRef.current;
|
|
2055
|
+
if (existing) {
|
|
2056
|
+
for (const track of existing.getTracks()) track.stop();
|
|
2057
|
+
narrationPreviewRef.current = null;
|
|
2058
|
+
setNarrationPreview(null);
|
|
1166
2059
|
}
|
|
1167
|
-
if (
|
|
2060
|
+
if (!narrationPreviewWanted) return;
|
|
1168
2061
|
let cancelled = false;
|
|
2062
|
+
let owned = null;
|
|
1169
2063
|
void (async () => {
|
|
1170
2064
|
try {
|
|
1171
|
-
const stream = await requestCameraStream({
|
|
2065
|
+
const stream = await requestCameraStream({
|
|
2066
|
+
video: cameraConstraints,
|
|
2067
|
+
audio: false
|
|
2068
|
+
});
|
|
2069
|
+
owned = stream;
|
|
1172
2070
|
if (cancelled) {
|
|
1173
2071
|
for (const track of stream.getTracks()) track.stop();
|
|
1174
2072
|
return;
|
|
@@ -1180,15 +2078,14 @@ function RecorderModal({
|
|
|
1180
2078
|
})();
|
|
1181
2079
|
return () => {
|
|
1182
2080
|
cancelled = true;
|
|
2081
|
+
if (owned && narrationPreviewRef.current === owned) {
|
|
2082
|
+
for (const track of owned.getTracks()) track.stop();
|
|
2083
|
+
narrationPreviewRef.current = null;
|
|
2084
|
+
setNarrationPreview(null);
|
|
2085
|
+
}
|
|
1183
2086
|
};
|
|
1184
|
-
}, [narrationPreviewWanted]);
|
|
1185
|
-
|
|
1186
|
-
return () => {
|
|
1187
|
-
const existing = narrationPreviewRef.current;
|
|
1188
|
-
if (existing) for (const track of existing.getTracks()) track.stop();
|
|
1189
|
-
};
|
|
1190
|
-
}, []);
|
|
1191
|
-
const handleNarrationPreview = useCallback2(async () => {
|
|
2087
|
+
}, [cameraConstraints, narrationPreviewWanted]);
|
|
2088
|
+
const handleNarrationPreview = useCallback3(async () => {
|
|
1192
2089
|
setNarrationRequesting(true);
|
|
1193
2090
|
try {
|
|
1194
2091
|
const controller = stageRef.current.controller;
|
|
@@ -1197,7 +2094,7 @@ function RecorderModal({
|
|
|
1197
2094
|
setNarrationRequesting(false);
|
|
1198
2095
|
}
|
|
1199
2096
|
}, []);
|
|
1200
|
-
const handleNarrationRecord =
|
|
2097
|
+
const handleNarrationRecord = useCallback3(() => {
|
|
1201
2098
|
void stageRef.current.recorder.start();
|
|
1202
2099
|
}, []);
|
|
1203
2100
|
const narrationCameraStream = narrationOn ? stage.recorder.cameraStream ?? narrationPreview : null;
|
|
@@ -1209,7 +2106,7 @@ function RecorderModal({
|
|
|
1209
2106
|
cameraPreviewRef,
|
|
1210
2107
|
!narrationOn && isDual && recorder.state !== "stopped" ? recorder.camera?.stream ?? null : null
|
|
1211
2108
|
);
|
|
1212
|
-
|
|
2109
|
+
useEffect3(() => {
|
|
1213
2110
|
setPlaybackPositionMs(0);
|
|
1214
2111
|
if (!recorder.blob) {
|
|
1215
2112
|
setPlaybackUrl(null);
|
|
@@ -1222,7 +2119,7 @@ function RecorderModal({
|
|
|
1222
2119
|
};
|
|
1223
2120
|
}, [recorder.blob]);
|
|
1224
2121
|
const cameraBlob = recorder.camera?.blob ?? null;
|
|
1225
|
-
|
|
2122
|
+
useEffect3(() => {
|
|
1226
2123
|
if (!cameraBlob) {
|
|
1227
2124
|
setCameraPlaybackUrl(null);
|
|
1228
2125
|
return;
|
|
@@ -1233,17 +2130,17 @@ function RecorderModal({
|
|
|
1233
2130
|
URL.revokeObjectURL(url);
|
|
1234
2131
|
};
|
|
1235
2132
|
}, [cameraBlob]);
|
|
1236
|
-
const captureKey = `${source}:${cameraOn ? micOn : ""}:${includeSystemAudio}`;
|
|
2133
|
+
const captureKey = `${source}:${cameraOn ? micOn : ""}:${includeSystemAudio}:${JSON.stringify(deviceSettings)}`;
|
|
1237
2134
|
const previousKeyRef = useRef2(captureKey);
|
|
1238
2135
|
const dualSaveProgressRef = useRef2({});
|
|
1239
|
-
|
|
2136
|
+
useEffect3(() => {
|
|
1240
2137
|
if (previousKeyRef.current !== captureKey) {
|
|
1241
2138
|
previousKeyRef.current = captureKey;
|
|
1242
2139
|
dualSaveProgressRef.current = {};
|
|
1243
2140
|
recorder.cancel();
|
|
1244
2141
|
}
|
|
1245
2142
|
}, [captureKey, recorder]);
|
|
1246
|
-
const handleClose =
|
|
2143
|
+
const handleClose = useCallback3(() => {
|
|
1247
2144
|
const s = stageRef.current;
|
|
1248
2145
|
if (closeNeedsConfirm(narrationOn, s.recorder.state, s.recorder.take !== null)) {
|
|
1249
2146
|
if (!window.confirm("Discard the current narration take?")) return;
|
|
@@ -1268,23 +2165,23 @@ function RecorderModal({
|
|
|
1268
2165
|
stage.controller.transport
|
|
1269
2166
|
)
|
|
1270
2167
|
});
|
|
1271
|
-
const handleRequest =
|
|
2168
|
+
const handleRequest = useCallback3(async () => {
|
|
1272
2169
|
setSaveError(null);
|
|
1273
2170
|
try {
|
|
1274
2171
|
await recorder.request();
|
|
1275
2172
|
} catch {
|
|
1276
2173
|
}
|
|
1277
2174
|
}, [recorder]);
|
|
1278
|
-
const handleStart =
|
|
2175
|
+
const handleStart = useCallback3(() => {
|
|
1279
2176
|
setSaveError(null);
|
|
1280
2177
|
dualSaveProgressRef.current = {};
|
|
1281
2178
|
recorder.start();
|
|
1282
2179
|
}, [recorder]);
|
|
1283
|
-
const handleStop =
|
|
2180
|
+
const handleStop = useCallback3(async () => {
|
|
1284
2181
|
setSaveError(null);
|
|
1285
2182
|
await recorder.stop();
|
|
1286
2183
|
}, [recorder]);
|
|
1287
|
-
const handleSave =
|
|
2184
|
+
const handleSave = useCallback3(async () => {
|
|
1288
2185
|
if (!recorder.blob || !recorder.mimeType || !recorder.extension || !recorder.directory) {
|
|
1289
2186
|
setSaveError("Nothing to save yet \u2014 record something first.");
|
|
1290
2187
|
return;
|
|
@@ -1423,11 +2320,11 @@ function RecorderModal({
|
|
|
1423
2320
|
onSave,
|
|
1424
2321
|
handleClose
|
|
1425
2322
|
]);
|
|
1426
|
-
const handleDiscard =
|
|
2323
|
+
const handleDiscard = useCallback3(() => {
|
|
1427
2324
|
dualSaveProgressRef.current = {};
|
|
1428
2325
|
recorder.reset();
|
|
1429
2326
|
}, [recorder]);
|
|
1430
|
-
const handlePlaybackTimeUpdate =
|
|
2327
|
+
const handlePlaybackTimeUpdate = useCallback3(
|
|
1431
2328
|
(media) => {
|
|
1432
2329
|
const currentMs = Number.isFinite(media.currentTime) ? media.currentTime * 1e3 : 0;
|
|
1433
2330
|
setPlaybackPositionMs(Math.min(recorder.durationMs, Math.max(0, currentMs)));
|
|
@@ -1471,6 +2368,7 @@ function RecorderModal({
|
|
|
1471
2368
|
recorder.blob !== null || recorder.camera?.blob != null,
|
|
1472
2369
|
stage.recorder.state
|
|
1473
2370
|
);
|
|
2371
|
+
const deviceSettingsLocked = narrationOn ? !narrationRecorderIdle : togglesLocked;
|
|
1474
2372
|
const narrationToggleFor = (key) => {
|
|
1475
2373
|
switch (key) {
|
|
1476
2374
|
case "mic":
|
|
@@ -1506,14 +2404,14 @@ function RecorderModal({
|
|
|
1506
2404
|
};
|
|
1507
2405
|
}
|
|
1508
2406
|
};
|
|
1509
|
-
return /* @__PURE__ */
|
|
2407
|
+
return /* @__PURE__ */ jsx2(
|
|
1510
2408
|
"div",
|
|
1511
2409
|
{
|
|
1512
2410
|
ref: overlayRef,
|
|
1513
2411
|
className: "squisq-editor-shell squisq-recorder-overlay",
|
|
1514
2412
|
"data-theme": colorScheme,
|
|
1515
2413
|
style: { ...overlayStyle, ...recorderThemeStyle(colorScheme) },
|
|
1516
|
-
children: /* @__PURE__ */
|
|
2414
|
+
children: /* @__PURE__ */ jsxs2(
|
|
1517
2415
|
"div",
|
|
1518
2416
|
{
|
|
1519
2417
|
ref: dialogRef,
|
|
@@ -1530,15 +2428,15 @@ function RecorderModal({
|
|
|
1530
2428
|
"aria-labelledby": headingId,
|
|
1531
2429
|
tabIndex: -1,
|
|
1532
2430
|
children: [
|
|
1533
|
-
/* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
1535
|
-
/* @__PURE__ */
|
|
1536
|
-
/* @__PURE__ */
|
|
1537
|
-
groupIndex > 0 && /* @__PURE__ */
|
|
1538
|
-
/* @__PURE__ */
|
|
2431
|
+
/* @__PURE__ */ jsx2("h2", { id: headingId, style: titleStyle, children: "Record media" }),
|
|
2432
|
+
/* @__PURE__ */ jsxs2("div", { style: narrationOn ? bodyRowStyle : void 0, children: [
|
|
2433
|
+
/* @__PURE__ */ jsxs2("div", { style: narrationOn ? leftColStyle : void 0, children: [
|
|
2434
|
+
/* @__PURE__ */ jsx2("div", { style: toggleRowStyle, role: "group", "aria-label": "Capture sources", children: TOGGLE_GROUPS.map((group, groupIndex) => /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2435
|
+
groupIndex > 0 && /* @__PURE__ */ jsx2("div", { "aria-hidden": "true", style: groupDividerStyle }),
|
|
2436
|
+
/* @__PURE__ */ jsx2("div", { style: toggleGroupStyle, children: group.toggles.map((t) => {
|
|
1539
2437
|
if (t.key === "systemAudio" && !canIncludeSystemAudio) return null;
|
|
1540
2438
|
const props = narrationOn ? narrationToggleFor(t.key) : simpleToggleProps(t.key);
|
|
1541
|
-
return /* @__PURE__ */
|
|
2439
|
+
return /* @__PURE__ */ jsx2(
|
|
1542
2440
|
"button",
|
|
1543
2441
|
{
|
|
1544
2442
|
type: "button",
|
|
@@ -1553,9 +2451,9 @@ function RecorderModal({
|
|
|
1553
2451
|
);
|
|
1554
2452
|
}) })
|
|
1555
2453
|
] }, group.label)) }),
|
|
1556
|
-
/* @__PURE__ */
|
|
1557
|
-
narrationAvailable && /* @__PURE__ */
|
|
1558
|
-
/* @__PURE__ */
|
|
2454
|
+
/* @__PURE__ */ jsx2("p", { style: summaryStyle, children: narrationOn ? narrationCaptureSummary(stage.recorder.withCamera) : captureSummary(micOn, cameraOn, screenOn, includeSystemAudio) }),
|
|
2455
|
+
narrationAvailable && /* @__PURE__ */ jsxs2("label", { style: checkboxRowStyle, children: [
|
|
2456
|
+
/* @__PURE__ */ jsx2(
|
|
1559
2457
|
"input",
|
|
1560
2458
|
{
|
|
1561
2459
|
type: "checkbox",
|
|
@@ -1568,10 +2466,25 @@ function RecorderModal({
|
|
|
1568
2466
|
),
|
|
1569
2467
|
"Show narration mode"
|
|
1570
2468
|
] }),
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
2469
|
+
/* @__PURE__ */ jsx2(
|
|
2470
|
+
RecorderDeviceSettingsPanel,
|
|
2471
|
+
{
|
|
2472
|
+
value: deviceSettings,
|
|
2473
|
+
onChange: handleDeviceSettingsChange,
|
|
2474
|
+
disabled: deviceSettingsLocked,
|
|
2475
|
+
microphoneEnabled: narrationOn ? true : micOn,
|
|
2476
|
+
cameraEnabled: narrationOn ? stage.recorder.withCamera : cameraOn,
|
|
2477
|
+
screenEnabled: narrationOn ? false : screenOn,
|
|
2478
|
+
systemAudioEnabled: !narrationOn && includeSystemAudio,
|
|
2479
|
+
separateAudioRecorder: narrationOn,
|
|
2480
|
+
primaryStream: narrationOn ? stage.controller.mic.stream : recorder.stream,
|
|
2481
|
+
cameraStream: narrationOn ? narrationCameraStream : recorder.camera?.stream ?? null
|
|
2482
|
+
}
|
|
2483
|
+
),
|
|
2484
|
+
!narrationOn && recorder.error && /* @__PURE__ */ jsx2("div", { style: errorStyle, children: recorder.error.message }),
|
|
2485
|
+
!narrationOn && saveError && /* @__PURE__ */ jsx2("div", { style: errorStyle, children: saveError }),
|
|
2486
|
+
narrationOn && (stage.recorder.error ?? stage.controller.mic.error) && /* @__PURE__ */ jsx2("div", { style: errorStyle, children: (stage.recorder.error ?? stage.controller.mic.error)?.message }),
|
|
2487
|
+
narrationOn && narrationCameraStream && /* @__PURE__ */ jsx2("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx2(
|
|
1575
2488
|
"video",
|
|
1576
2489
|
{
|
|
1577
2490
|
ref: previewRef,
|
|
@@ -1581,10 +2494,10 @@ function RecorderModal({
|
|
|
1581
2494
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
1582
2495
|
}
|
|
1583
2496
|
) }),
|
|
1584
|
-
narrationOn && !narrationCameraStream && narrationTakeDone && /* @__PURE__ */
|
|
1585
|
-
narrationOn && !narrationCameraStream && !narrationTakeDone && stage.recorder.withCamera && /* @__PURE__ */
|
|
1586
|
-
narrationOn && !narrationCameraStream && !narrationTakeDone && !stage.recorder.withCamera && /* @__PURE__ */
|
|
1587
|
-
/* @__PURE__ */
|
|
2497
|
+
narrationOn && !narrationCameraStream && narrationTakeDone && /* @__PURE__ */ jsx2("div", { style: audioMeterStyle, children: stage.recorder.take ? `\u2713 Recorded ${formatDurationMs(stage.recorder.take.durationSec * 1e3)}` : "\u25CF Processing take\u2026" }),
|
|
2498
|
+
narrationOn && !narrationCameraStream && !narrationTakeDone && stage.recorder.withCamera && /* @__PURE__ */ jsx2("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx2("span", { children: narrationPreviewWanted ? "Camera starting\u2026" : "Click Start preview to turn on your camera." }) }),
|
|
2499
|
+
narrationOn && !narrationCameraStream && !narrationTakeDone && !stage.recorder.withCamera && /* @__PURE__ */ jsxs2("div", { style: { ...audioMeterStyle, position: "relative", overflow: "hidden" }, children: [
|
|
2500
|
+
/* @__PURE__ */ jsx2(
|
|
1588
2501
|
"div",
|
|
1589
2502
|
{
|
|
1590
2503
|
"aria-hidden": "true",
|
|
@@ -1594,11 +2507,11 @@ function RecorderModal({
|
|
|
1594
2507
|
}
|
|
1595
2508
|
}
|
|
1596
2509
|
),
|
|
1597
|
-
/* @__PURE__ */
|
|
2510
|
+
/* @__PURE__ */ jsx2("span", { style: { position: "relative" }, children: stage.recorder.state === "recording" ? "\u25CF Recording narration" : narrationMicLive ? stage.controller.voiceActive ? "Voice detected" : "Microphone ready" : "Click Start preview to check your mic." })
|
|
1598
2511
|
] }),
|
|
1599
|
-
!narrationOn && !showPreview && /* @__PURE__ */
|
|
1600
|
-
!narrationOn && showPreview && recorder.state !== "stopped" && !isAudioOnly && /* @__PURE__ */
|
|
1601
|
-
/* @__PURE__ */
|
|
2512
|
+
!narrationOn && !showPreview && /* @__PURE__ */ jsx2("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx2("span", { children: "Click Start Preview to start a recording." }) }),
|
|
2513
|
+
!narrationOn && showPreview && recorder.state !== "stopped" && !isAudioOnly && /* @__PURE__ */ jsxs2("div", { style: isDual ? { ...previewBoxStyle, position: "relative" } : previewBoxStyle, children: [
|
|
2514
|
+
/* @__PURE__ */ jsx2(
|
|
1602
2515
|
"video",
|
|
1603
2516
|
{
|
|
1604
2517
|
ref: previewRef,
|
|
@@ -1608,7 +2521,7 @@ function RecorderModal({
|
|
|
1608
2521
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
1609
2522
|
}
|
|
1610
2523
|
),
|
|
1611
|
-
isDual && /* @__PURE__ */
|
|
2524
|
+
isDual && /* @__PURE__ */ jsx2(
|
|
1612
2525
|
"video",
|
|
1613
2526
|
{
|
|
1614
2527
|
ref: cameraPreviewRef,
|
|
@@ -1629,12 +2542,12 @@ function RecorderModal({
|
|
|
1629
2542
|
}
|
|
1630
2543
|
)
|
|
1631
2544
|
] }),
|
|
1632
|
-
!narrationOn && showPreview && recorder.state !== "stopped" && isAudioOnly && /* @__PURE__ */
|
|
2545
|
+
!narrationOn && showPreview && recorder.state !== "stopped" && isAudioOnly && /* @__PURE__ */ jsx2("div", { style: audioMeterStyle, children: recorder.state === "recording" ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
1633
2546
|
"\u25CF Recording ",
|
|
1634
2547
|
formatDurationMs(recorder.durationMs)
|
|
1635
|
-
] }) : /* @__PURE__ */
|
|
1636
|
-
!narrationOn && recorder.state === "stopped" && playbackUrl && !isAudioOnly && /* @__PURE__ */
|
|
1637
|
-
/* @__PURE__ */
|
|
2548
|
+
] }) : /* @__PURE__ */ jsx2(Fragment3, { children: "Microphone ready" }) }),
|
|
2549
|
+
!narrationOn && recorder.state === "stopped" && playbackUrl && !isAudioOnly && /* @__PURE__ */ jsxs2("div", { style: { ...previewBoxStyle, position: "relative" }, children: [
|
|
2550
|
+
/* @__PURE__ */ jsx2(
|
|
1638
2551
|
"video",
|
|
1639
2552
|
{
|
|
1640
2553
|
src: playbackUrl,
|
|
@@ -1646,7 +2559,7 @@ function RecorderModal({
|
|
|
1646
2559
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
1647
2560
|
}
|
|
1648
2561
|
),
|
|
1649
|
-
/* @__PURE__ */
|
|
2562
|
+
/* @__PURE__ */ jsxs2(
|
|
1650
2563
|
"div",
|
|
1651
2564
|
{
|
|
1652
2565
|
role: "timer",
|
|
@@ -1660,9 +2573,9 @@ function RecorderModal({
|
|
|
1660
2573
|
}
|
|
1661
2574
|
)
|
|
1662
2575
|
] }),
|
|
1663
|
-
!narrationOn && recorder.state === "stopped" && isDual && cameraPlaybackUrl && /* @__PURE__ */
|
|
1664
|
-
/* @__PURE__ */
|
|
1665
|
-
/* @__PURE__ */
|
|
2576
|
+
!narrationOn && recorder.state === "stopped" && isDual && cameraPlaybackUrl && /* @__PURE__ */ jsxs2("div", { style: { marginBottom: 12 }, children: [
|
|
2577
|
+
/* @__PURE__ */ jsx2("div", { style: summaryStyle, children: "Camera (picture-in-picture)" }),
|
|
2578
|
+
/* @__PURE__ */ jsx2(
|
|
1666
2579
|
"video",
|
|
1667
2580
|
{
|
|
1668
2581
|
src: cameraPlaybackUrl,
|
|
@@ -1678,16 +2591,16 @@ function RecorderModal({
|
|
|
1678
2591
|
}
|
|
1679
2592
|
)
|
|
1680
2593
|
] }),
|
|
1681
|
-
!narrationOn && recorder.state === "stopped" && playbackUrl && isAudioOnly && /* @__PURE__ */
|
|
1682
|
-
/* @__PURE__ */
|
|
2594
|
+
!narrationOn && recorder.state === "stopped" && playbackUrl && isAudioOnly && /* @__PURE__ */ jsxs2("div", { style: { marginBottom: 12 }, children: [
|
|
2595
|
+
/* @__PURE__ */ jsxs2("div", { style: { ...audioMeterStyle, marginBottom: 8 }, children: [
|
|
1683
2596
|
"\u2713 Recorded ",
|
|
1684
2597
|
formatDurationMs(recorder.durationMs)
|
|
1685
2598
|
] }),
|
|
1686
|
-
/* @__PURE__ */
|
|
2599
|
+
/* @__PURE__ */ jsx2("audio", { src: playbackUrl, controls: true, style: { width: "100%" } })
|
|
1687
2600
|
] }),
|
|
1688
|
-
!narrationOn && source === "mic" && /* @__PURE__ */
|
|
1689
|
-
/* @__PURE__ */
|
|
1690
|
-
/* @__PURE__ */
|
|
2601
|
+
!narrationOn && source === "mic" && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2602
|
+
/* @__PURE__ */ jsx2("label", { style: labelStyle, htmlFor: "recorder-source-text", children: "Script (used to auto-match this narration to a block)" }),
|
|
2603
|
+
/* @__PURE__ */ jsx2(
|
|
1691
2604
|
"textarea",
|
|
1692
2605
|
{
|
|
1693
2606
|
id: "recorder-source-text",
|
|
@@ -1699,25 +2612,25 @@ function RecorderModal({
|
|
|
1699
2612
|
}
|
|
1700
2613
|
)
|
|
1701
2614
|
] }),
|
|
1702
|
-
/* @__PURE__ */
|
|
1703
|
-
/* @__PURE__ */
|
|
2615
|
+
/* @__PURE__ */ jsx2("label", { style: labelStyle, htmlFor: "recorder-basename", children: "Filename (optional)" }),
|
|
2616
|
+
/* @__PURE__ */ jsx2(
|
|
1704
2617
|
"input",
|
|
1705
2618
|
{
|
|
1706
2619
|
id: "recorder-basename",
|
|
1707
2620
|
type: "text",
|
|
1708
|
-
style:
|
|
2621
|
+
style: inputStyle2,
|
|
1709
2622
|
placeholder: narrationOn ? "narration" : isDual ? "screen + camera" : filenameSeed,
|
|
1710
2623
|
value: basename,
|
|
1711
2624
|
onChange: (e) => setBasename(e.target.value),
|
|
1712
2625
|
disabled: narrationOn ? !narrationRecorderIdle : recorder.state === "recording"
|
|
1713
2626
|
}
|
|
1714
2627
|
),
|
|
1715
|
-
!narrationOn && recorder.state === "recording" && !isAudioOnly && /* @__PURE__ */
|
|
2628
|
+
!narrationOn && recorder.state === "recording" && !isAudioOnly && /* @__PURE__ */ jsxs2("div", { style: recordingStatusStyle, children: [
|
|
1716
2629
|
"\u25CF Recording ",
|
|
1717
2630
|
formatDurationMs(recorder.durationMs)
|
|
1718
2631
|
] }),
|
|
1719
|
-
/* @__PURE__ */
|
|
1720
|
-
/* @__PURE__ */
|
|
2632
|
+
/* @__PURE__ */ jsxs2("div", { style: buttonRowStyle, children: [
|
|
2633
|
+
/* @__PURE__ */ jsx2(
|
|
1721
2634
|
"button",
|
|
1722
2635
|
{
|
|
1723
2636
|
type: "button",
|
|
@@ -1727,8 +2640,8 @@ function RecorderModal({
|
|
|
1727
2640
|
children: "Close"
|
|
1728
2641
|
}
|
|
1729
2642
|
),
|
|
1730
|
-
narrationOn && /* @__PURE__ */
|
|
1731
|
-
narrationRecorderIdle && !narrationMicLive && /* @__PURE__ */
|
|
2643
|
+
narrationOn && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2644
|
+
narrationRecorderIdle && !narrationMicLive && /* @__PURE__ */ jsx2(
|
|
1732
2645
|
"button",
|
|
1733
2646
|
{
|
|
1734
2647
|
type: "button",
|
|
@@ -1738,14 +2651,14 @@ function RecorderModal({
|
|
|
1738
2651
|
children: narrationRequesting ? "Requesting\u2026" : "Start preview"
|
|
1739
2652
|
}
|
|
1740
2653
|
),
|
|
1741
|
-
narrationRecorderIdle && narrationMicLive && /* @__PURE__ */
|
|
1742
|
-
/* @__PURE__ */
|
|
2654
|
+
narrationRecorderIdle && narrationMicLive && /* @__PURE__ */ jsxs2("button", { type: "button", style: btnRecord, onClick: handleNarrationRecord, children: [
|
|
2655
|
+
/* @__PURE__ */ jsx2(
|
|
1743
2656
|
"span",
|
|
1744
2657
|
{
|
|
1745
2658
|
className: "squisq-recorder-record-dot",
|
|
1746
2659
|
style: recordDotFrameStyle,
|
|
1747
2660
|
"aria-hidden": "true",
|
|
1748
|
-
children: /* @__PURE__ */
|
|
2661
|
+
children: /* @__PURE__ */ jsx2(
|
|
1749
2662
|
"span",
|
|
1750
2663
|
{
|
|
1751
2664
|
className: "squisq-recorder-record-dot-center",
|
|
@@ -1756,7 +2669,7 @@ function RecorderModal({
|
|
|
1756
2669
|
),
|
|
1757
2670
|
"Record"
|
|
1758
2671
|
] }),
|
|
1759
|
-
(stage.recorder.state === "recording" || stage.recorder.state === "starting") && /* @__PURE__ */
|
|
2672
|
+
(stage.recorder.state === "recording" || stage.recorder.state === "starting") && /* @__PURE__ */ jsx2(
|
|
1760
2673
|
"button",
|
|
1761
2674
|
{
|
|
1762
2675
|
type: "button",
|
|
@@ -1765,11 +2678,11 @@ function RecorderModal({
|
|
|
1765
2678
|
children: "Stop"
|
|
1766
2679
|
}
|
|
1767
2680
|
),
|
|
1768
|
-
stage.recorder.state === "processing" && /* @__PURE__ */
|
|
1769
|
-
stage.recorder.state === "saving" && /* @__PURE__ */
|
|
1770
|
-
stage.recorder.state === "review" && stage.recorder.take && /* @__PURE__ */
|
|
1771
|
-
/* @__PURE__ */
|
|
1772
|
-
/* @__PURE__ */
|
|
2681
|
+
stage.recorder.state === "processing" && /* @__PURE__ */ jsx2("span", { style: recordingStatusStyle, children: "Aligning take\u2026" }),
|
|
2682
|
+
stage.recorder.state === "saving" && /* @__PURE__ */ jsx2("span", { style: recordingStatusStyle, children: "Saving\u2026" }),
|
|
2683
|
+
stage.recorder.state === "review" && stage.recorder.take && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2684
|
+
/* @__PURE__ */ jsx2("button", { type: "button", style: btnSecondary, onClick: stage.handleRetake, children: "Discard & re-record" }),
|
|
2685
|
+
/* @__PURE__ */ jsx2(
|
|
1773
2686
|
"button",
|
|
1774
2687
|
{
|
|
1775
2688
|
type: "button",
|
|
@@ -1780,8 +2693,8 @@ function RecorderModal({
|
|
|
1780
2693
|
)
|
|
1781
2694
|
] })
|
|
1782
2695
|
] }),
|
|
1783
|
-
!narrationOn && /* @__PURE__ */
|
|
1784
|
-
(recorder.state === "idle" || recorder.state === "error" || recorder.state === "requesting") && /* @__PURE__ */
|
|
2696
|
+
!narrationOn && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2697
|
+
(recorder.state === "idle" || recorder.state === "error" || recorder.state === "requesting") && /* @__PURE__ */ jsx2(
|
|
1785
2698
|
"button",
|
|
1786
2699
|
{
|
|
1787
2700
|
type: "button",
|
|
@@ -1791,14 +2704,14 @@ function RecorderModal({
|
|
|
1791
2704
|
children: recorder.state === "requesting" ? "Requesting\u2026" : "Start preview"
|
|
1792
2705
|
}
|
|
1793
2706
|
),
|
|
1794
|
-
canRecord && /* @__PURE__ */
|
|
1795
|
-
/* @__PURE__ */
|
|
2707
|
+
canRecord && /* @__PURE__ */ jsxs2("button", { type: "button", style: btnRecord, onClick: handleStart, disabled: isBusy, children: [
|
|
2708
|
+
/* @__PURE__ */ jsx2(
|
|
1796
2709
|
"span",
|
|
1797
2710
|
{
|
|
1798
2711
|
className: "squisq-recorder-record-dot",
|
|
1799
2712
|
style: recordDotFrameStyle,
|
|
1800
2713
|
"aria-hidden": "true",
|
|
1801
|
-
children: /* @__PURE__ */
|
|
2714
|
+
children: /* @__PURE__ */ jsx2(
|
|
1802
2715
|
"span",
|
|
1803
2716
|
{
|
|
1804
2717
|
className: "squisq-recorder-record-dot-center",
|
|
@@ -1809,9 +2722,9 @@ function RecorderModal({
|
|
|
1809
2722
|
),
|
|
1810
2723
|
"Record"
|
|
1811
2724
|
] }),
|
|
1812
|
-
canStop && /* @__PURE__ */
|
|
1813
|
-
canSave && /* @__PURE__ */
|
|
1814
|
-
/* @__PURE__ */
|
|
2725
|
+
canStop && /* @__PURE__ */ jsx2("button", { type: "button", style: btnDanger, onClick: handleStop, disabled: isBusy, children: "Stop" }),
|
|
2726
|
+
canSave && /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
2727
|
+
/* @__PURE__ */ jsx2(
|
|
1815
2728
|
"button",
|
|
1816
2729
|
{
|
|
1817
2730
|
type: "button",
|
|
@@ -1821,7 +2734,7 @@ function RecorderModal({
|
|
|
1821
2734
|
children: "Discard & re-record"
|
|
1822
2735
|
}
|
|
1823
2736
|
),
|
|
1824
|
-
/* @__PURE__ */
|
|
2737
|
+
/* @__PURE__ */ jsx2(
|
|
1825
2738
|
"button",
|
|
1826
2739
|
{
|
|
1827
2740
|
type: "button",
|
|
@@ -1835,7 +2748,7 @@ function RecorderModal({
|
|
|
1835
2748
|
] })
|
|
1836
2749
|
] })
|
|
1837
2750
|
] }),
|
|
1838
|
-
narrationOn && narration && /* @__PURE__ */
|
|
2751
|
+
narrationOn && narration && /* @__PURE__ */ jsx2("div", { style: rightColStyle, children: /* @__PURE__ */ jsx2(
|
|
1839
2752
|
NarrationStage,
|
|
1840
2753
|
{
|
|
1841
2754
|
stage,
|
|
@@ -1856,9 +2769,9 @@ function RecorderModal({
|
|
|
1856
2769
|
}
|
|
1857
2770
|
|
|
1858
2771
|
// src/recorder/RecorderPanel.tsx
|
|
1859
|
-
import { useCallback as
|
|
2772
|
+
import { useCallback as useCallback4, useState as useState4 } from "react";
|
|
1860
2773
|
import { createPortal } from "react-dom";
|
|
1861
|
-
import { Fragment as
|
|
2774
|
+
import { Fragment as Fragment4, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1862
2775
|
function RecorderPanel({
|
|
1863
2776
|
mediaProvider,
|
|
1864
2777
|
container = null,
|
|
@@ -1872,18 +2785,18 @@ function RecorderPanel({
|
|
|
1872
2785
|
onOpenChange,
|
|
1873
2786
|
showTrigger = true
|
|
1874
2787
|
}) {
|
|
1875
|
-
const [uncontrolledOpen, setUncontrolledOpen] =
|
|
2788
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState4(false);
|
|
1876
2789
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
1877
|
-
const setOpen =
|
|
2790
|
+
const setOpen = useCallback4(
|
|
1878
2791
|
(nextOpen) => {
|
|
1879
2792
|
if (controlledOpen === void 0) setUncontrolledOpen(nextOpen);
|
|
1880
2793
|
onOpenChange?.(nextOpen);
|
|
1881
2794
|
},
|
|
1882
2795
|
[controlledOpen, onOpenChange]
|
|
1883
2796
|
);
|
|
1884
|
-
const handleClose =
|
|
1885
|
-
return /* @__PURE__ */
|
|
1886
|
-
showTrigger && /* @__PURE__ */
|
|
2797
|
+
const handleClose = useCallback4(() => setOpen(false), [setOpen]);
|
|
2798
|
+
return /* @__PURE__ */ jsxs3(Fragment4, { children: [
|
|
2799
|
+
showTrigger && /* @__PURE__ */ jsx3(
|
|
1887
2800
|
"button",
|
|
1888
2801
|
{
|
|
1889
2802
|
type: "button",
|
|
@@ -1892,11 +2805,11 @@ function RecorderPanel({
|
|
|
1892
2805
|
"aria-label": tooltip,
|
|
1893
2806
|
"aria-expanded": open,
|
|
1894
2807
|
onClick: () => setOpen(!open),
|
|
1895
|
-
children: /* @__PURE__ */
|
|
2808
|
+
children: /* @__PURE__ */ jsx3(Icon, { icon: "fa-solid fa-microphone" })
|
|
1896
2809
|
}
|
|
1897
2810
|
),
|
|
1898
2811
|
open && typeof document !== "undefined" && createPortal(
|
|
1899
|
-
/* @__PURE__ */
|
|
2812
|
+
/* @__PURE__ */ jsx3(
|
|
1900
2813
|
RecorderModal,
|
|
1901
2814
|
{
|
|
1902
2815
|
mediaProvider,
|
|
@@ -1919,6 +2832,13 @@ export {
|
|
|
1919
2832
|
requestScreenStream,
|
|
1920
2833
|
getCaptureKind,
|
|
1921
2834
|
useMediaRecorder,
|
|
2835
|
+
RecorderDeviceSettingsPanel,
|
|
2836
|
+
DEFAULT_RECORDER_DEVICE_SETTINGS,
|
|
2837
|
+
buildRecorderAudioConstraints,
|
|
2838
|
+
buildRecorderCameraConstraints,
|
|
2839
|
+
buildRecorderScreenConstraints,
|
|
2840
|
+
buildRecorderScreenAudioConstraints,
|
|
2841
|
+
recorderBitsPerSecond,
|
|
1922
2842
|
useModalDialog,
|
|
1923
2843
|
RecorderModal,
|
|
1924
2844
|
RecorderPanel
|