@bendyline/squisq-editor-react 2.11.3 → 2.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-PMNNJYFD.js → chunk-34FRFDQ6.js} +138 -30
- package/dist/{chunk-7RRYZULY.js → chunk-BJ3TXAIQ.js} +155 -15
- package/dist/{chunk-AAIZHMVD.js → chunk-CDISORBP.js} +3 -3
- package/dist/{chunk-VH45VMPL.js → chunk-DN6XFOY2.js} +1 -1
- package/dist/{chunk-UNOKKSAC.js → chunk-ENDRPV6T.js} +1 -1
- package/dist/{chunk-A2W4GYPG.js → chunk-ES6CPRCW.js} +5 -4
- package/dist/{chunk-SK3MQSHQ.js → chunk-UYKOTWJM.js} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -7
- package/dist/json-editor/index.js +2 -2
- package/dist/recorder/index.d.ts +2 -2
- package/dist/recorder/index.js +3 -3
- package/dist/{recorder-GrEh4xE8.d.ts → recorder-B6MtQH5u.d.ts} +4 -2
- 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-B6r9Zlq-.d.ts → useNarrationStage-D3Sgcf0L.d.ts} +19 -0
- package/package.json +6 -6
|
@@ -1344,6 +1344,17 @@ import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef4
|
|
|
1344
1344
|
import {
|
|
1345
1345
|
alignNarration
|
|
1346
1346
|
} from "@bendyline/squisq/narration";
|
|
1347
|
+
|
|
1348
|
+
// src/recorder/recordingLimits.ts
|
|
1349
|
+
var DEFAULT_MAX_RECORDING_BYTES = 900 * 1024 * 1024;
|
|
1350
|
+
function resolveMaxRecordingBytes(value) {
|
|
1351
|
+
return value !== void 0 && Number.isSafeInteger(value) && value > 0 ? value : DEFAULT_MAX_RECORDING_BYTES;
|
|
1352
|
+
}
|
|
1353
|
+
function formatRecordingBytes(bytes) {
|
|
1354
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// src/teleprompter/recording/useNarrationRecorder.ts
|
|
1347
1358
|
var TRACE_INTERVAL_MS = 250;
|
|
1348
1359
|
function mixdownToMono(buffer) {
|
|
1349
1360
|
const channels = buffer.numberOfChannels;
|
|
@@ -1377,6 +1388,11 @@ function stopRecorder(recorder) {
|
|
|
1377
1388
|
function useNarrationRecorder(options) {
|
|
1378
1389
|
const [state, setState] = useState4("idle");
|
|
1379
1390
|
const [error, setError] = useState4(null);
|
|
1391
|
+
const [recordedBytes, setRecordedBytes] = useState4(0);
|
|
1392
|
+
const [limitReached, setLimitReached] = useState4(false);
|
|
1393
|
+
const maxRecordingBytes = resolveMaxRecordingBytes(options.maxRecordingBytes);
|
|
1394
|
+
const stopRef = useRef4(async () => {
|
|
1395
|
+
});
|
|
1380
1396
|
const [withCamera, setWithCamera] = useState4(false);
|
|
1381
1397
|
const [cameraStream, setCameraStream] = useState4(null);
|
|
1382
1398
|
const [take, setTake] = useState4(null);
|
|
@@ -1423,8 +1439,11 @@ function useNarrationRecorder(options) {
|
|
|
1423
1439
|
const superseded = () => generationRef.current !== generation;
|
|
1424
1440
|
startingRef.current = true;
|
|
1425
1441
|
setError(null);
|
|
1442
|
+
setRecordedBytes(0);
|
|
1443
|
+
setLimitReached(false);
|
|
1426
1444
|
applyTake(null);
|
|
1427
1445
|
setState("starting");
|
|
1446
|
+
const recordingByteLimit = resolveMaxRecordingBytes(opts.maxRecordingBytes);
|
|
1428
1447
|
let camera = null;
|
|
1429
1448
|
let audioRecorder = null;
|
|
1430
1449
|
let cameraRecorder = null;
|
|
@@ -1493,17 +1512,30 @@ function useNarrationRecorder(options) {
|
|
|
1493
1512
|
traceTimer: null,
|
|
1494
1513
|
startedAtMs: performance.now(),
|
|
1495
1514
|
audioStartMs: null,
|
|
1496
|
-
cameraStartMs: null
|
|
1515
|
+
cameraStartMs: null,
|
|
1516
|
+
recordedBytes: 0,
|
|
1517
|
+
limitReached: false
|
|
1518
|
+
};
|
|
1519
|
+
const retainChunk = (chunks, chunk) => {
|
|
1520
|
+
if (chunk.size === 0 || superseded()) return;
|
|
1521
|
+
chunks.push(chunk);
|
|
1522
|
+
capture.recordedBytes += chunk.size;
|
|
1523
|
+
setRecordedBytes(capture.recordedBytes);
|
|
1524
|
+
if (!capture.limitReached && capture.recordedBytes >= recordingByteLimit) {
|
|
1525
|
+
capture.limitReached = true;
|
|
1526
|
+
setLimitReached(true);
|
|
1527
|
+
if (captureRef.current === capture) void stopRef.current();
|
|
1528
|
+
}
|
|
1497
1529
|
};
|
|
1498
1530
|
audioRecorder.ondataavailable = (e) => {
|
|
1499
|
-
|
|
1531
|
+
retainChunk(capture.audioChunks, e.data);
|
|
1500
1532
|
};
|
|
1501
1533
|
audioRecorder.onstart = () => {
|
|
1502
1534
|
capture.audioStartMs = performance.now();
|
|
1503
1535
|
};
|
|
1504
1536
|
if (cameraRecorder) {
|
|
1505
1537
|
cameraRecorder.ondataavailable = (e) => {
|
|
1506
|
-
|
|
1538
|
+
retainChunk(capture.cameraChunks, e.data);
|
|
1507
1539
|
};
|
|
1508
1540
|
cameraRecorder.onstart = () => {
|
|
1509
1541
|
capture.cameraStartMs = performance.now();
|
|
@@ -1552,8 +1584,10 @@ function useNarrationRecorder(options) {
|
|
|
1552
1584
|
optionsRef.current.onRecordingStop?.();
|
|
1553
1585
|
processingRef.current = true;
|
|
1554
1586
|
setState("processing");
|
|
1555
|
-
await
|
|
1556
|
-
|
|
1587
|
+
await Promise.all([
|
|
1588
|
+
stopRecorder(capture.audioRecorder),
|
|
1589
|
+
...capture.cameraRecorder ? [stopRecorder(capture.cameraRecorder)] : []
|
|
1590
|
+
]);
|
|
1557
1591
|
for (const track of capture.cameraStream?.getTracks() ?? []) track.stop();
|
|
1558
1592
|
setCameraStream(null);
|
|
1559
1593
|
const audioMime = capture.audioRecorder.mimeType || capture.audioMime;
|
|
@@ -1613,16 +1647,21 @@ function useNarrationRecorder(options) {
|
|
|
1613
1647
|
});
|
|
1614
1648
|
setState("review");
|
|
1615
1649
|
}, [applyTake, cancelPendingStart]);
|
|
1650
|
+
stopRef.current = stop;
|
|
1616
1651
|
const retake = useCallback4(() => {
|
|
1617
1652
|
teardownCapture();
|
|
1618
1653
|
applyTake(null);
|
|
1619
1654
|
setError(null);
|
|
1655
|
+
setRecordedBytes(0);
|
|
1656
|
+
setLimitReached(false);
|
|
1620
1657
|
setState("idle");
|
|
1621
1658
|
}, [applyTake, teardownCapture]);
|
|
1622
1659
|
const discard = useCallback4(() => {
|
|
1623
1660
|
teardownCapture();
|
|
1624
1661
|
applyTake(null);
|
|
1625
1662
|
setError(null);
|
|
1663
|
+
setRecordedBytes(0);
|
|
1664
|
+
setLimitReached(false);
|
|
1626
1665
|
setState("idle");
|
|
1627
1666
|
}, [applyTake, teardownCapture]);
|
|
1628
1667
|
const beginSave = useCallback4(() => setState("saving"), []);
|
|
@@ -1631,6 +1670,8 @@ function useNarrationRecorder(options) {
|
|
|
1631
1670
|
if (ok) {
|
|
1632
1671
|
applyTake(null);
|
|
1633
1672
|
setError(null);
|
|
1673
|
+
setRecordedBytes(0);
|
|
1674
|
+
setLimitReached(false);
|
|
1634
1675
|
setState("idle");
|
|
1635
1676
|
} else {
|
|
1636
1677
|
setError(saveError ?? new Error("Save failed"));
|
|
@@ -1658,6 +1699,9 @@ function useNarrationRecorder(options) {
|
|
|
1658
1699
|
return {
|
|
1659
1700
|
state,
|
|
1660
1701
|
error,
|
|
1702
|
+
recordedBytes,
|
|
1703
|
+
maxRecordingBytes,
|
|
1704
|
+
limitReached,
|
|
1661
1705
|
withCamera,
|
|
1662
1706
|
setWithCamera,
|
|
1663
1707
|
cameraStream,
|
|
@@ -1818,6 +1862,7 @@ function useNarrationStage(opts) {
|
|
|
1818
1862
|
getWordPos: () => controllerRef.current.wordPos,
|
|
1819
1863
|
getMicDeviceId: () => controllerRef.current.prefs.micDeviceId,
|
|
1820
1864
|
cameraConstraints: opts.cameraConstraints,
|
|
1865
|
+
maxRecordingBytes: opts.maxRecordingBytes,
|
|
1821
1866
|
audioRecorderOptions: opts.audioRecorderOptions,
|
|
1822
1867
|
cameraRecorderOptions: opts.cameraRecorderOptions,
|
|
1823
1868
|
onRecordingStart: () => controllerRef.current.play(),
|
|
@@ -2379,7 +2424,7 @@ function TeleprompterControls({
|
|
|
2379
2424
|
}
|
|
2380
2425
|
|
|
2381
2426
|
// src/teleprompter/NarrationStage.tsx
|
|
2382
|
-
import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef8 } from "react";
|
|
2427
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef8, useState as useState6 } from "react";
|
|
2383
2428
|
import { createPortal } from "react-dom";
|
|
2384
2429
|
|
|
2385
2430
|
// src/teleprompter/TeleprompterSelfView.tsx
|
|
@@ -2517,6 +2562,47 @@ function drawPrompterFrame(canvas, frame) {
|
|
|
2517
2562
|
|
|
2518
2563
|
// src/teleprompter/NarrationStage.tsx
|
|
2519
2564
|
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2565
|
+
function NarrationTakeBackups({ take, baseWpm }) {
|
|
2566
|
+
const [downloads, setDownloads] = useState6(
|
|
2567
|
+
[]
|
|
2568
|
+
);
|
|
2569
|
+
useEffect8(() => {
|
|
2570
|
+
const timing = buildNarrationSavePlan({
|
|
2571
|
+
script: take.script,
|
|
2572
|
+
alignment: take.alignment,
|
|
2573
|
+
durationSec: take.durationSec,
|
|
2574
|
+
audioExt: take.audioExt,
|
|
2575
|
+
cameraExt: take.cameraExt,
|
|
2576
|
+
cameraOffsetSec: take.cameraOffsetSec,
|
|
2577
|
+
baseWpm
|
|
2578
|
+
}).sidecarPayload;
|
|
2579
|
+
const assets = [
|
|
2580
|
+
{
|
|
2581
|
+
label: "Download audio backup",
|
|
2582
|
+
blob: take.audioBlob,
|
|
2583
|
+
filename: "narration" + take.audioExt
|
|
2584
|
+
},
|
|
2585
|
+
...take.cameraBlob ? [
|
|
2586
|
+
{
|
|
2587
|
+
label: "Download camera backup",
|
|
2588
|
+
blob: take.cameraBlob,
|
|
2589
|
+
filename: "narration-camera" + (take.cameraExt ?? ".webm")
|
|
2590
|
+
}
|
|
2591
|
+
] : [],
|
|
2592
|
+
{
|
|
2593
|
+
label: "Download timing backup",
|
|
2594
|
+
blob: new Blob([JSON.stringify(timing, null, 2)], { type: "application/json" }),
|
|
2595
|
+
filename: "narration" + take.audioExt + ".timing.json"
|
|
2596
|
+
}
|
|
2597
|
+
];
|
|
2598
|
+
const next = assets.map(({ blob, ...asset }) => ({ ...asset, url: URL.createObjectURL(blob) }));
|
|
2599
|
+
setDownloads(next);
|
|
2600
|
+
return () => {
|
|
2601
|
+
for (const download of next) URL.revokeObjectURL(download.url);
|
|
2602
|
+
};
|
|
2603
|
+
}, [take, baseWpm]);
|
|
2604
|
+
return downloads.map(({ label, url, filename }) => /* @__PURE__ */ jsx4("a", { href: url, download: filename, children: label }, label));
|
|
2605
|
+
}
|
|
2520
2606
|
function NarrationStage(props) {
|
|
2521
2607
|
const {
|
|
2522
2608
|
stage,
|
|
@@ -2632,32 +2718,45 @@ function NarrationStage(props) {
|
|
|
2632
2718
|
const script = controller.script;
|
|
2633
2719
|
const portalOpen = float.portalTarget !== null;
|
|
2634
2720
|
const busyRecording = recorder.state === "recording" || recorder.state === "starting";
|
|
2635
|
-
const recordSlot = recording && showRecordSlot ? /* @__PURE__ */
|
|
2636
|
-
/* @__PURE__ */
|
|
2637
|
-
"
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
children: "\u23FA Record"
|
|
2643
|
-
}
|
|
2644
|
-
),
|
|
2645
|
-
showCameraToggleInRecordSlot ? /* @__PURE__ */ jsxs3("label", { title: "Also capture your camera as a separate video file", children: [
|
|
2721
|
+
const recordSlot = recording && showRecordSlot ? /* @__PURE__ */ jsxs3("span", { className: "squisq-teleprompter-group", "data-testid": "teleprompter-record", children: [
|
|
2722
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
2723
|
+
"Auto-stops at ",
|
|
2724
|
+
formatRecordingBytes(recorder.maxRecordingBytes),
|
|
2725
|
+
"."
|
|
2726
|
+
] }),
|
|
2727
|
+
recorder.state === "idle" || recorder.state === "error" ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
2646
2728
|
/* @__PURE__ */ jsx4(
|
|
2647
|
-
"
|
|
2729
|
+
"button",
|
|
2648
2730
|
{
|
|
2649
|
-
type: "
|
|
2650
|
-
|
|
2651
|
-
|
|
2731
|
+
type: "button",
|
|
2732
|
+
onClick: () => void recorder.start(),
|
|
2733
|
+
title: "Record narration while you read",
|
|
2734
|
+
children: "\u23FA Record"
|
|
2652
2735
|
}
|
|
2653
2736
|
),
|
|
2654
|
-
"camera"
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2737
|
+
showCameraToggleInRecordSlot ? /* @__PURE__ */ jsxs3("label", { title: "Also capture your camera as a separate video file", children: [
|
|
2738
|
+
/* @__PURE__ */ jsx4(
|
|
2739
|
+
"input",
|
|
2740
|
+
{
|
|
2741
|
+
type: "checkbox",
|
|
2742
|
+
checked: recorder.withCamera,
|
|
2743
|
+
onChange: (e) => recorder.setWithCamera(e.target.checked)
|
|
2744
|
+
}
|
|
2745
|
+
),
|
|
2746
|
+
"camera"
|
|
2747
|
+
] }) : null,
|
|
2748
|
+
recorder.state === "error" ? /* @__PURE__ */ jsxs3("span", { title: recorder.error?.message, children: [
|
|
2749
|
+
"\u26A0 ",
|
|
2750
|
+
recorder.error?.message
|
|
2751
|
+
] }) : null
|
|
2752
|
+
] }) : busyRecording ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
2753
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
2754
|
+
formatRecordingBytes(recorder.recordedBytes),
|
|
2755
|
+
" recorded"
|
|
2756
|
+
] }),
|
|
2757
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: () => void recorder.stop(), children: "\u23F9 Stop" })
|
|
2758
|
+
] }) : recorder.state === "processing" ? /* @__PURE__ */ jsx4("span", { children: "Aligning take\u2026" }) : recorder.state === "saving" ? /* @__PURE__ */ jsx4("span", { children: "Saving\u2026" }) : null
|
|
2759
|
+
] }) : null;
|
|
2661
2760
|
return /* @__PURE__ */ jsxs3("div", { ref: rootRef, className: "squisq-teleprompter-root", "data-testid": "teleprompter-view", children: [
|
|
2662
2761
|
/* @__PURE__ */ jsxs3("div", { className: "squisq-teleprompter-stage", children: [
|
|
2663
2762
|
portalOpen ? /* @__PURE__ */ jsxs3("div", { className: "squisq-teleprompter-float-note", children: [
|
|
@@ -2689,6 +2788,11 @@ function NarrationStage(props) {
|
|
|
2689
2788
|
) : null,
|
|
2690
2789
|
showSelfView ? /* @__PURE__ */ jsx4(TeleprompterSelfView, { stream: recorder.cameraStream }) : null
|
|
2691
2790
|
] }),
|
|
2791
|
+
recorder.limitReached ? /* @__PURE__ */ jsxs3("div", { className: "squisq-teleprompter-review", role: "status", children: [
|
|
2792
|
+
"Recording stopped at the ",
|
|
2793
|
+
formatRecordingBytes(recorder.maxRecordingBytes),
|
|
2794
|
+
" size limit. The complete take is retained; save it or download a backup before leaving."
|
|
2795
|
+
] }) : null,
|
|
2692
2796
|
recorder.state === "review" && recorder.take ? /* @__PURE__ */ jsxs3("div", { className: "squisq-teleprompter-review", "data-testid": "teleprompter-review", children: [
|
|
2693
2797
|
/* @__PURE__ */ jsxs3("span", { children: [
|
|
2694
2798
|
"Take: ",
|
|
@@ -2704,14 +2808,16 @@ function NarrationStage(props) {
|
|
|
2704
2808
|
onTimeUpdate: stage.handleReviewTimeUpdate
|
|
2705
2809
|
}
|
|
2706
2810
|
) : null,
|
|
2811
|
+
/* @__PURE__ */ jsx4(NarrationTakeBackups, { take: recorder.take, baseWpm: controller.prefs.baseWpm }),
|
|
2707
2812
|
showReviewActions ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
2708
2813
|
/* @__PURE__ */ jsx4("button", { type: "button", onClick: () => void stage.handleSave(), children: "\u2713 Save narration" }),
|
|
2709
2814
|
/* @__PURE__ */ jsx4("button", { type: "button", onClick: stage.handleRetake, children: "\u21BA Retake" }),
|
|
2710
2815
|
/* @__PURE__ */ jsx4("button", { type: "button", onClick: stage.handleDiscard, children: "\u2715 Discard" })
|
|
2711
2816
|
] }) : null,
|
|
2712
|
-
recorder.error ? /* @__PURE__ */ jsxs3("span", { children: [
|
|
2817
|
+
recorder.error ? /* @__PURE__ */ jsxs3("span", { role: "alert", children: [
|
|
2713
2818
|
"\u26A0 ",
|
|
2714
|
-
recorder.error.message
|
|
2819
|
+
recorder.error.message,
|
|
2820
|
+
" Your take is still available. Download a backup before leaving."
|
|
2715
2821
|
] }) : null
|
|
2716
2822
|
] }) : null,
|
|
2717
2823
|
stage.saveNotice ? /* @__PURE__ */ jsxs3("div", { className: "squisq-teleprompter-review", "data-testid": "teleprompter-save-notice", children: [
|
|
@@ -2731,6 +2837,8 @@ function NarrationStage(props) {
|
|
|
2731
2837
|
}
|
|
2732
2838
|
|
|
2733
2839
|
export {
|
|
2840
|
+
resolveMaxRecordingBytes,
|
|
2841
|
+
formatRecordingBytes,
|
|
2734
2842
|
resolveFormat,
|
|
2735
2843
|
supportsMediaRecorder,
|
|
2736
2844
|
supportsUserMedia,
|
|
@@ -7,9 +7,11 @@ import {
|
|
|
7
7
|
buildTimingJson,
|
|
8
8
|
encodeNarrationTimingJson,
|
|
9
9
|
encodeTimingJson,
|
|
10
|
+
formatRecordingBytes,
|
|
10
11
|
requestCameraStream,
|
|
11
12
|
requestMicStream,
|
|
12
13
|
resolveFormat,
|
|
14
|
+
resolveMaxRecordingBytes,
|
|
13
15
|
supportsDisplayMedia,
|
|
14
16
|
supportsMediaRecorder,
|
|
15
17
|
supportsSystemAudioCapture,
|
|
@@ -17,7 +19,7 @@ import {
|
|
|
17
19
|
timingPathFor,
|
|
18
20
|
useNarrationStage,
|
|
19
21
|
useStreamPreview
|
|
20
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-34FRFDQ6.js";
|
|
21
23
|
|
|
22
24
|
// src/recorder/sources/screenStream.ts
|
|
23
25
|
function mixAudioTracks(streams) {
|
|
@@ -245,6 +247,9 @@ function getCaptureKind(source) {
|
|
|
245
247
|
}
|
|
246
248
|
function useMediaRecorder(options = {}) {
|
|
247
249
|
const [state, setState] = useState("idle");
|
|
250
|
+
const [recordedBytes, setRecordedBytes] = useState(0);
|
|
251
|
+
const [limitReached, setLimitReached] = useState(false);
|
|
252
|
+
const recordedBytesRef = useRef(0);
|
|
248
253
|
const [stream, setStream] = useState(null);
|
|
249
254
|
const [blob, setBlob] = useState(null);
|
|
250
255
|
const [format, setFormat] = useState(null);
|
|
@@ -320,7 +325,23 @@ function useMediaRecorder(options = {}) {
|
|
|
320
325
|
setCamera(null);
|
|
321
326
|
setCameraOffsetSec(null);
|
|
322
327
|
}, []);
|
|
328
|
+
const resetByteCount = useCallback(() => {
|
|
329
|
+
recordedBytesRef.current = 0;
|
|
330
|
+
setRecordedBytes(0);
|
|
331
|
+
setLimitReached(false);
|
|
332
|
+
}, []);
|
|
333
|
+
const recordChunk = useCallback((data, chunks) => {
|
|
334
|
+
if (data.size === 0) return;
|
|
335
|
+
chunks.push(data);
|
|
336
|
+
recordedBytesRef.current += data.size;
|
|
337
|
+
setRecordedBytes(recordedBytesRef.current);
|
|
338
|
+
if (stateRef.current === "recording" && recordedBytesRef.current >= resolveMaxRecordingBytes(optionsRef.current.maxRecordingBytes)) {
|
|
339
|
+
setLimitReached(true);
|
|
340
|
+
void stopFnRef.current?.();
|
|
341
|
+
}
|
|
342
|
+
}, []);
|
|
323
343
|
const reset = useCallback(() => {
|
|
344
|
+
resetByteCount();
|
|
324
345
|
setBlob(null);
|
|
325
346
|
setDurationMs(0);
|
|
326
347
|
setError(null);
|
|
@@ -336,8 +357,9 @@ function useMediaRecorder(options = {}) {
|
|
|
336
357
|
} else {
|
|
337
358
|
cancelFnRef.current?.();
|
|
338
359
|
}
|
|
339
|
-
}, [clearTicker, transition]);
|
|
360
|
+
}, [clearTicker, resetByteCount, transition]);
|
|
340
361
|
const cancel = useCallback(() => {
|
|
362
|
+
resetByteCount();
|
|
341
363
|
lifecycleRef.current += 1;
|
|
342
364
|
const rec = recorderRef.current;
|
|
343
365
|
if (rec && rec.state !== "inactive") {
|
|
@@ -363,7 +385,7 @@ function useMediaRecorder(options = {}) {
|
|
|
363
385
|
setDurationMs(0);
|
|
364
386
|
setError(null);
|
|
365
387
|
transition("idle");
|
|
366
|
-
}, [clearTicker, releaseStream, releaseSecondary, transition]);
|
|
388
|
+
}, [clearTicker, releaseStream, releaseSecondary, resetByteCount, transition]);
|
|
367
389
|
const request = useCallback(async () => {
|
|
368
390
|
if (requestPromiseRef.current) return requestPromiseRef.current;
|
|
369
391
|
if (recorderRef.current?.stream.active) return;
|
|
@@ -471,7 +493,8 @@ function useMediaRecorder(options = {}) {
|
|
|
471
493
|
stopPromiseRef.current = null;
|
|
472
494
|
};
|
|
473
495
|
primary.ondataavailable = (e) => {
|
|
474
|
-
if (
|
|
496
|
+
if (lifecycle !== lifecycleRef.current || recorderRef.current !== primary) return;
|
|
497
|
+
if (e.data) recordChunk(e.data, chunksRef.current);
|
|
475
498
|
};
|
|
476
499
|
primary.onstart = () => {
|
|
477
500
|
primaryStartMsRef.current = performance.now();
|
|
@@ -479,7 +502,9 @@ function useMediaRecorder(options = {}) {
|
|
|
479
502
|
primary.onstop = () => laneStopped(primary);
|
|
480
503
|
primary.onerror = (e) => laneError(primary, e);
|
|
481
504
|
secondary.ondataavailable = (e) => {
|
|
482
|
-
|
|
505
|
+
const lane = secondaryRef.current;
|
|
506
|
+
if (lifecycle !== lifecycleRef.current || lane?.recorder !== secondary) return;
|
|
507
|
+
if (e.data) recordChunk(e.data, lane.chunks);
|
|
483
508
|
};
|
|
484
509
|
secondary.onstart = () => {
|
|
485
510
|
secondaryStartMsRef.current = performance.now();
|
|
@@ -526,7 +551,8 @@ function useMediaRecorder(options = {}) {
|
|
|
526
551
|
}
|
|
527
552
|
const recorder = new MediaRecorder(nextStream, recorderOptions);
|
|
528
553
|
recorder.ondataavailable = (e) => {
|
|
529
|
-
if (
|
|
554
|
+
if (lifecycle !== lifecycleRef.current || recorderRef.current !== recorder) return;
|
|
555
|
+
if (e.data) recordChunk(e.data, chunksRef.current);
|
|
530
556
|
};
|
|
531
557
|
recorder.onstop = () => {
|
|
532
558
|
if (recorderRef.current !== recorder || lifecycle !== lifecycleRef.current) return;
|
|
@@ -585,7 +611,7 @@ function useMediaRecorder(options = {}) {
|
|
|
585
611
|
})();
|
|
586
612
|
requestPromiseRef.current = requestPromise;
|
|
587
613
|
return requestPromise;
|
|
588
|
-
}, [clearTicker, deactivateCapture, transition]);
|
|
614
|
+
}, [clearTicker, deactivateCapture, recordChunk, transition]);
|
|
589
615
|
const start = useCallback(() => {
|
|
590
616
|
const rec = recorderRef.current;
|
|
591
617
|
if (!rec) {
|
|
@@ -595,6 +621,7 @@ function useMediaRecorder(options = {}) {
|
|
|
595
621
|
return;
|
|
596
622
|
}
|
|
597
623
|
if (rec.state === "recording") return;
|
|
624
|
+
resetByteCount();
|
|
598
625
|
chunksRef.current = [];
|
|
599
626
|
if (secondaryRef.current) secondaryRef.current.chunks = [];
|
|
600
627
|
setBlob(null);
|
|
@@ -634,7 +661,7 @@ function useMediaRecorder(options = {}) {
|
|
|
634
661
|
setDurationMs(Date.now() - startTimestampRef.current);
|
|
635
662
|
}
|
|
636
663
|
}, 100);
|
|
637
|
-
}, [clearTicker, deactivateCapture, transition]);
|
|
664
|
+
}, [clearTicker, deactivateCapture, resetByteCount, transition]);
|
|
638
665
|
const getElapsedMs = useCallback(() => {
|
|
639
666
|
if (stateRef.current !== "recording") return null;
|
|
640
667
|
const startedAt = startTimestampRef.current;
|
|
@@ -647,6 +674,10 @@ function useMediaRecorder(options = {}) {
|
|
|
647
674
|
return Promise.resolve(blob);
|
|
648
675
|
}
|
|
649
676
|
transition("stopping");
|
|
677
|
+
clearTicker();
|
|
678
|
+
if (startTimestampRef.current !== null) {
|
|
679
|
+
setDurationMs(Math.max(0, Date.now() - startTimestampRef.current));
|
|
680
|
+
}
|
|
650
681
|
const secondary = secondaryRef.current;
|
|
651
682
|
const secondaryActive = secondary != null && secondary.recorder.state !== "inactive";
|
|
652
683
|
pendingLanesRef.current = secondaryActive ? 2 : 1;
|
|
@@ -706,6 +737,9 @@ function useMediaRecorder(options = {}) {
|
|
|
706
737
|
};
|
|
707
738
|
}, [releaseStream, releaseSecondary, clearTicker]);
|
|
708
739
|
return {
|
|
740
|
+
recordedBytes,
|
|
741
|
+
maxRecordingBytes: resolveMaxRecordingBytes(options.maxRecordingBytes),
|
|
742
|
+
limitReached,
|
|
709
743
|
state,
|
|
710
744
|
stream,
|
|
711
745
|
blob,
|
|
@@ -2397,7 +2431,8 @@ function RecorderModal({
|
|
|
2397
2431
|
onSave,
|
|
2398
2432
|
narration = null,
|
|
2399
2433
|
slides = null,
|
|
2400
|
-
title = "Record media"
|
|
2434
|
+
title = "Record media",
|
|
2435
|
+
maxRecordingBytes
|
|
2401
2436
|
}) {
|
|
2402
2437
|
const initialToggles = toggleStateFromMode(initialMode);
|
|
2403
2438
|
const [micOn, setMicOn] = useState3(initialToggles.micOn);
|
|
@@ -2454,6 +2489,7 @@ function RecorderModal({
|
|
|
2454
2489
|
const encoding = deviceSettings.encoding;
|
|
2455
2490
|
const recorder = useMediaRecorder({
|
|
2456
2491
|
source,
|
|
2492
|
+
maxRecordingBytes,
|
|
2457
2493
|
includeMicrophone: cameraOn ? micOn : void 0,
|
|
2458
2494
|
audioConstraints,
|
|
2459
2495
|
videoConstraints: cameraConstraints,
|
|
@@ -2477,6 +2513,7 @@ function RecorderModal({
|
|
|
2477
2513
|
basenameRef.current = basename;
|
|
2478
2514
|
const stage = useNarrationStage({
|
|
2479
2515
|
doc: narration?.doc ?? null,
|
|
2516
|
+
maxRecordingBytes,
|
|
2480
2517
|
recording: narration?.recording ?? null,
|
|
2481
2518
|
getAudioBasename: () => basenameRef.current.trim() || void 0,
|
|
2482
2519
|
micConstraints: audioConstraints,
|
|
@@ -2681,6 +2718,13 @@ function RecorderModal({
|
|
|
2681
2718
|
}
|
|
2682
2719
|
}, [captureKey, recorder]);
|
|
2683
2720
|
const handleClose = useCallback4(() => {
|
|
2721
|
+
if (!narrationOn) {
|
|
2722
|
+
if (isSaving || recorder.state === "stopping" || recorder.state === "requesting") return;
|
|
2723
|
+
if ((recorder.blob || recorder.camera?.blob || recorder.state === "recording") && !window.confirm(
|
|
2724
|
+
"Discard this recording? Download or save it before closing to keep a copy."
|
|
2725
|
+
))
|
|
2726
|
+
return;
|
|
2727
|
+
}
|
|
2684
2728
|
const s = stageRef.current;
|
|
2685
2729
|
if (closeNeedsConfirm(narrationOn, s.recorder.state, s.recorder.take !== null)) {
|
|
2686
2730
|
if (!window.confirm("Discard the current narration take?")) return;
|
|
@@ -2694,7 +2738,7 @@ function RecorderModal({
|
|
|
2694
2738
|
}
|
|
2695
2739
|
recorder.cancel();
|
|
2696
2740
|
onClose();
|
|
2697
|
-
}, [narrationOn, recorder, onClose]);
|
|
2741
|
+
}, [narrationOn, recorder, onClose, isSaving]);
|
|
2698
2742
|
useModalDialog({
|
|
2699
2743
|
rootRef: overlayRef,
|
|
2700
2744
|
dialogRef,
|
|
@@ -2822,7 +2866,8 @@ function RecorderModal({
|
|
|
2822
2866
|
};
|
|
2823
2867
|
dualSaveProgressRef.current = {};
|
|
2824
2868
|
onSave?.(result);
|
|
2825
|
-
|
|
2869
|
+
recorder.cancel();
|
|
2870
|
+
onClose();
|
|
2826
2871
|
} catch (err) {
|
|
2827
2872
|
setSaveError(err instanceof Error ? err.message : "Failed to save recording");
|
|
2828
2873
|
} finally {
|
|
@@ -2876,7 +2921,8 @@ function RecorderModal({
|
|
|
2876
2921
|
result.sourceText = slideTiming ? void 0 : sourceText;
|
|
2877
2922
|
}
|
|
2878
2923
|
onSave?.(result);
|
|
2879
|
-
|
|
2924
|
+
recorder.cancel();
|
|
2925
|
+
onClose();
|
|
2880
2926
|
} catch (err) {
|
|
2881
2927
|
setSaveError(err instanceof Error ? err.message : "Failed to save recording");
|
|
2882
2928
|
} finally {
|
|
@@ -2895,7 +2941,7 @@ function RecorderModal({
|
|
|
2895
2941
|
mediaProvider,
|
|
2896
2942
|
container,
|
|
2897
2943
|
onSave,
|
|
2898
|
-
|
|
2944
|
+
onClose,
|
|
2899
2945
|
writeSlideTimingSidecar
|
|
2900
2946
|
]);
|
|
2901
2947
|
const handleDiscard = useCallback4(() => {
|
|
@@ -2927,8 +2973,47 @@ function RecorderModal({
|
|
|
2927
2973
|
() => slides?.doc && showTimingCheckbox ? advanceCoverage(slides.doc, advanceLog) : null,
|
|
2928
2974
|
[slides?.doc, showTimingCheckbox, advanceLog]
|
|
2929
2975
|
);
|
|
2976
|
+
const [timingDownloadUrl, setTimingDownloadUrl] = useState3(null);
|
|
2977
|
+
const downloadFilename = useMemo(
|
|
2978
|
+
() => !recorder.blob ? "" : buildFilename(
|
|
2979
|
+
source === "mic" ? "audio" : "video",
|
|
2980
|
+
recorder.extension ?? ".webm",
|
|
2981
|
+
isDual && basename.trim() ? `${basename.trim()}-screen` : basename,
|
|
2982
|
+
filenameSeed
|
|
2983
|
+
),
|
|
2984
|
+
[source, recorder.extension, recorder.blob, isDual, basename, filenameSeed]
|
|
2985
|
+
);
|
|
2986
|
+
const timingDownloadFilename = `${downloadFilename}.timing.json`;
|
|
2987
|
+
useEffect4(() => {
|
|
2988
|
+
if (narrationOn || !canSave) {
|
|
2989
|
+
setTimingDownloadUrl(null);
|
|
2990
|
+
return;
|
|
2991
|
+
}
|
|
2992
|
+
const duration = recorder.durationMs / 1e3;
|
|
2993
|
+
const encoded = slidesOn && slidesCaptureTimings && applySlideTimings && slides?.doc && advanceLog.length > 0 ? encodeNarrationTimingJson(buildAdvanceTimingJson(slides.doc, advanceLog, duration)) : source === "mic" ? encodeTimingJson(buildTimingJson(sourceText, duration)) : null;
|
|
2994
|
+
if (encoded === null) {
|
|
2995
|
+
setTimingDownloadUrl(null);
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2998
|
+
const url = URL.createObjectURL(
|
|
2999
|
+
new Blob([new Uint8Array(encoded)], { type: "application/json" })
|
|
3000
|
+
);
|
|
3001
|
+
setTimingDownloadUrl(url);
|
|
3002
|
+
return () => URL.revokeObjectURL(url);
|
|
3003
|
+
}, [
|
|
3004
|
+
narrationOn,
|
|
3005
|
+
canSave,
|
|
3006
|
+
recorder.durationMs,
|
|
3007
|
+
slidesOn,
|
|
3008
|
+
slidesCaptureTimings,
|
|
3009
|
+
applySlideTimings,
|
|
3010
|
+
slides?.doc,
|
|
3011
|
+
advanceLog,
|
|
3012
|
+
source,
|
|
3013
|
+
sourceText
|
|
3014
|
+
]);
|
|
2930
3015
|
const slideCoverageWarning = slideCoverage ? unshownSlidesWarning(slideCoverage.total, slideCoverage.unshown) : null;
|
|
2931
|
-
const togglesLocked = recorder.state === "recording" || recorder.state === "requesting" || canSave;
|
|
3016
|
+
const togglesLocked = recorder.state === "recording" || recorder.state === "requesting" || recorder.state === "stopping" || canSave;
|
|
2932
3017
|
const toggleLockReason = canSave ? "Save or discard this recording before changing sources" : void 0;
|
|
2933
3018
|
const systemAudioHasCompanion = micOn || cameraOn || screenOn;
|
|
2934
3019
|
const simpleToggleProps = (key) => {
|
|
@@ -3110,7 +3195,25 @@ function RecorderModal({
|
|
|
3110
3195
|
}
|
|
3111
3196
|
),
|
|
3112
3197
|
!narrationOn && recorder.error && /* @__PURE__ */ jsx5("div", { style: errorStyle, children: recorder.error.message }),
|
|
3113
|
-
!narrationOn && saveError && /* @__PURE__ */
|
|
3198
|
+
!narrationOn && saveError && /* @__PURE__ */ jsxs4("div", { role: "alert", style: errorStyle, children: [
|
|
3199
|
+
saveError,
|
|
3200
|
+
/* @__PURE__ */ jsx5("p", { style: { marginBottom: 0 }, children: "Your recording is still available below. Download a copy before closing, or try saving again." })
|
|
3201
|
+
] }),
|
|
3202
|
+
/* @__PURE__ */ jsxs4("p", { style: summaryStyle, children: [
|
|
3203
|
+
"Recording size:",
|
|
3204
|
+
" ",
|
|
3205
|
+
formatRecordingBytes(
|
|
3206
|
+
narrationOn ? stage.recorder.recordedBytes : recorder.recordedBytes
|
|
3207
|
+
),
|
|
3208
|
+
". Automatically stops at",
|
|
3209
|
+
" ",
|
|
3210
|
+
formatRecordingBytes(
|
|
3211
|
+
narrationOn ? stage.recorder.maxRecordingBytes : recorder.maxRecordingBytes
|
|
3212
|
+
),
|
|
3213
|
+
" ",
|
|
3214
|
+
"total. Final encoding may add more data."
|
|
3215
|
+
] }),
|
|
3216
|
+
!narrationOn && recorder.limitReached && /* @__PURE__ */ jsx5("p", { role: "status", style: recordingStatusStyle, children: "Recording stopped at the size limit. Your complete recording is retained; download a copy or save it to the document." }),
|
|
3114
3217
|
narrationOn && (stage.recorder.error ?? stage.controller.mic.error) && /* @__PURE__ */ jsx5("div", { style: errorStyle, children: (stage.recorder.error ?? stage.controller.mic.error)?.message }),
|
|
3115
3218
|
narrationOn && narrationCameraStream && /* @__PURE__ */ jsx5("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx5(
|
|
3116
3219
|
"video",
|
|
@@ -3226,6 +3329,43 @@ function RecorderModal({
|
|
|
3226
3329
|
] }),
|
|
3227
3330
|
/* @__PURE__ */ jsx5("audio", { src: playbackUrl, controls: true, style: { width: "100%" } })
|
|
3228
3331
|
] }),
|
|
3332
|
+
!narrationOn && canSave && playbackUrl && /* @__PURE__ */ jsxs4(
|
|
3333
|
+
"div",
|
|
3334
|
+
{
|
|
3335
|
+
style: {
|
|
3336
|
+
...buttonRowStyle,
|
|
3337
|
+
flexWrap: "wrap",
|
|
3338
|
+
justifyContent: "flex-start",
|
|
3339
|
+
marginBottom: 12
|
|
3340
|
+
},
|
|
3341
|
+
children: [
|
|
3342
|
+
/* @__PURE__ */ jsx5("a", { href: playbackUrl, download: downloadFilename, style: btnSecondary, children: isDual ? "Download screen recording" : "Download recording" }),
|
|
3343
|
+
isDual && cameraPlaybackUrl && /* @__PURE__ */ jsx5(
|
|
3344
|
+
"a",
|
|
3345
|
+
{
|
|
3346
|
+
href: cameraPlaybackUrl,
|
|
3347
|
+
download: buildFilename(
|
|
3348
|
+
"video",
|
|
3349
|
+
recorder.camera?.extension ?? ".webm",
|
|
3350
|
+
basename.trim() ? `${basename.trim()}-camera` : void 0,
|
|
3351
|
+
micOn ? "camera-audio" : "camera"
|
|
3352
|
+
),
|
|
3353
|
+
style: btnSecondary,
|
|
3354
|
+
children: "Download camera recording"
|
|
3355
|
+
}
|
|
3356
|
+
),
|
|
3357
|
+
timingDownloadUrl && /* @__PURE__ */ jsx5(
|
|
3358
|
+
"a",
|
|
3359
|
+
{
|
|
3360
|
+
href: timingDownloadUrl,
|
|
3361
|
+
download: timingDownloadFilename,
|
|
3362
|
+
style: btnSecondary,
|
|
3363
|
+
children: "Download recording timings"
|
|
3364
|
+
}
|
|
3365
|
+
)
|
|
3366
|
+
]
|
|
3367
|
+
}
|
|
3368
|
+
),
|
|
3229
3369
|
!narrationOn && !slidesTimingCapture && source === "mic" && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3230
3370
|
/* @__PURE__ */ jsx5("label", { style: labelStyle, htmlFor: "recorder-source-text", children: "Script (used to auto-match this narration to a block)" }),
|
|
3231
3371
|
/* @__PURE__ */ jsx5(
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
markdownToTiptap,
|
|
8
8
|
tiptapToMarkdown
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ES6CPRCW.js";
|
|
10
10
|
import {
|
|
11
11
|
ImageEditor,
|
|
12
12
|
ImageViewer,
|
|
@@ -19,13 +19,13 @@ import {
|
|
|
19
19
|
documentTitleFromFileName,
|
|
20
20
|
resolveBlockVisual,
|
|
21
21
|
useModalDialog
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-BJ3TXAIQ.js";
|
|
23
23
|
import {
|
|
24
24
|
Icon
|
|
25
25
|
} from "./chunk-GS7QWYFT.js";
|
|
26
26
|
import {
|
|
27
27
|
TeleprompterView
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-ENDRPV6T.js";
|
|
29
29
|
|
|
30
30
|
// src/fileKind.ts
|
|
31
31
|
var DATA_MODE_EXTENSIONS = /* @__PURE__ */ new Set(["csv", "tsv", "parquet"]);
|
|
@@ -10,8 +10,8 @@ var RE_BOLD_UNDER = /(?<![\p{L}\p{N}_])__(?![\s_])(.+?)(?<![\s_])__(?![\p{L}\p{N
|
|
|
10
10
|
var RE_ITALIC_STAR = /\*(?![\s*])(.+?)(?<![\s*])\*/g;
|
|
11
11
|
var RE_ITALIC_UNDER = /(?<![\p{L}\p{N}_])_(?![\s_])(.+?)(?<![\s_])_(?![\p{L}\p{N}_])/gu;
|
|
12
12
|
var RE_STRIKETHROUGH = /~~(.+?)~~/g;
|
|
13
|
-
var RE_LEGACY_BOLD_STAR = /\*\*(?![\s*])(
|
|
14
|
-
var RE_LEGACY_ITALIC_STAR = /(?<!\*)\*(?![\s*])(
|
|
13
|
+
var RE_LEGACY_BOLD_STAR = /\*\*(?![\s*])((?:(?!\*\*).)+?)(?<![\s*])([ \t]+)\*\*(?=$|[^\s*])/g;
|
|
14
|
+
var RE_LEGACY_ITALIC_STAR = /(?<!\*)\*(?![\s*])([^*]+?)(?<![\s*])([ \t]+)\*(?=$|[^\s*])/g;
|
|
15
15
|
var ESCAPABLE_MD_CHARS = ["*", "_", "~", "\\"];
|
|
16
16
|
var RE_MD_ESCAPE = /\\([*_~\\])/g;
|
|
17
17
|
var RE_INLINE_CODE = /`(.+?)`/g;
|
|
@@ -445,7 +445,7 @@ function tiptapToMarkdown(html) {
|
|
|
445
445
|
while ((cellExec = cellRegex.exec(rowHtml)) !== null) {
|
|
446
446
|
const tag = cellExec[1];
|
|
447
447
|
const attrs = cellExec[2];
|
|
448
|
-
const content = htmlToTableCell(cellExec[3]
|
|
448
|
+
const content = htmlToTableCell(cellExec[3]);
|
|
449
449
|
const alignExec = attrs.match(/text-align:\s*(left|center|right)/);
|
|
450
450
|
cells.push({
|
|
451
451
|
content,
|
|
@@ -1075,7 +1075,8 @@ function htmlToInline(html) {
|
|
|
1075
1075
|
return restoreLeadingSpaces(unescapeHtml(result));
|
|
1076
1076
|
}
|
|
1077
1077
|
function htmlToTableCell(html) {
|
|
1078
|
-
|
|
1078
|
+
const withParagraphBreaks = html.replace(/<\/p>\s*<p(?:\s[^>]*)?>/gi, "<br>").replace(/^\s*<p(?:\s[^>]*)?>/i, "").replace(/<\/p>\s*$/i, "");
|
|
1079
|
+
return htmlToInline(withParagraphBreaks).replace(/ {2}\n/g, "<br>");
|
|
1079
1080
|
}
|
|
1080
1081
|
function preserveLeadingSpaces(html) {
|
|
1081
1082
|
return html.replace(/^ +/, (spaces) => " ".repeat(spaces.length));
|
package/dist/index.d.ts
CHANGED
|
@@ -26,9 +26,9 @@ import { FenceRendererMap } from '@bendyline/squisq/fence';
|
|
|
26
26
|
import { TableViewState } from '@bendyline/squisq/table';
|
|
27
27
|
import { EditJournal } from '@bendyline/squisq-grid-react';
|
|
28
28
|
export { JsonEditor, JsonEditorProps } from './json-editor/index.js';
|
|
29
|
-
export { C as CameraStreamOptions, D as DEFAULT_RECORDER_DEVICE_SETTINGS, M as MediaDeviceInventory, R as RecordedBookmark, a as RecordedMediaKind, b as RecorderAudioDeviceSettings, c as RecorderButton, d as RecorderButtonProps, e as RecorderCameraDeviceSettings, f as RecorderCameraSaveResult, g as RecorderColorScheme, h as RecorderConstraintMode, i as RecorderDeviceOption, j as RecorderDeviceQuickPicks, k as RecorderDeviceQuickPicksProps, l as RecorderDeviceSettings, m as RecorderDeviceSettingsPanel, n as RecorderDeviceSettingsPanelProps, o as RecorderEncodingSettings, p as RecorderModal, q as RecorderModalProps, r as RecorderNarrationOptions, s as RecorderPanel, t as RecorderPanelProps, u as RecorderSaveResult, v as RecorderScreenAudioSettings, w as RecorderScreenDeviceSettings, x as RecorderSlidesOptions, S as ScreenStreamHandle, y as ScreenStreamOptions, z as SlideTimingSaveResult, T as TimingJson, A as buildRecorderAudioConstraints, B as buildRecorderCameraConstraints, E as buildRecorderScreenAudioConstraints, F as buildRecorderScreenConstraints, G as buildTimingJson, H as encodeTimingJson, I as hasRecorderDeviceChoice, J as recordedMediaKind, K as recorderBitsPerSecond, L as recorderDeviceGroups, N as recorderDeviceOptions, O as requestCameraStream, P as requestMicStream, Q as requestScreenStream, U as timingPathFor, V as useMediaDevices, W as useStreamPreview } from './recorder-
|
|
30
|
-
import { R as RecorderState } from './useNarrationStage-
|
|
31
|
-
export { C as CanvasSink, a as CaptureKind, D as DEFAULT_TELEPROMPTER_PREFS, F as FloatOpenOptions, b as FloatTier, c as FloatingWindowHandle, d as FloatingWindowManager, M as MicAnalysisHandle, e as MicAnalysisStatus, N as NarrationRecorderController, f as NarrationRecorderState, g as NarrationStageHandle, h as NarrationTake, P as PrompterTransport, i as RecorderAudioBitrateMode, j as RecorderCameraLane, k as RecorderExtendedMediaOptions, l as RecorderSource, m as ResolvedFormat, T as TeleprompterController, n as TeleprompterPrefs, o as TeleprompterRecordingDeps, U as UseMediaRecorderOptions, p as UseMediaRecorderResult, q as UseNarrationStageOptions, r as buildFilename, s as createFloatingWindowManager, t as detectFloatTiers, u as getCaptureKind, v as resolveFormat, w as supportsDisplayMedia, x as supportsMediaRecorder, y as supportsUserMedia, z as useFloatingWindow, A as useMediaRecorder, B as useMicAnalysis, E as useNarrationRecorder, G as useNarrationStage, H as useTeleprompter, I as vadConfigForSensitivity } from './useNarrationStage-
|
|
29
|
+
export { C as CameraStreamOptions, D as DEFAULT_RECORDER_DEVICE_SETTINGS, M as MediaDeviceInventory, R as RecordedBookmark, a as RecordedMediaKind, b as RecorderAudioDeviceSettings, c as RecorderButton, d as RecorderButtonProps, e as RecorderCameraDeviceSettings, f as RecorderCameraSaveResult, g as RecorderColorScheme, h as RecorderConstraintMode, i as RecorderDeviceOption, j as RecorderDeviceQuickPicks, k as RecorderDeviceQuickPicksProps, l as RecorderDeviceSettings, m as RecorderDeviceSettingsPanel, n as RecorderDeviceSettingsPanelProps, o as RecorderEncodingSettings, p as RecorderModal, q as RecorderModalProps, r as RecorderNarrationOptions, s as RecorderPanel, t as RecorderPanelProps, u as RecorderSaveResult, v as RecorderScreenAudioSettings, w as RecorderScreenDeviceSettings, x as RecorderSlidesOptions, S as ScreenStreamHandle, y as ScreenStreamOptions, z as SlideTimingSaveResult, T as TimingJson, A as buildRecorderAudioConstraints, B as buildRecorderCameraConstraints, E as buildRecorderScreenAudioConstraints, F as buildRecorderScreenConstraints, G as buildTimingJson, H as encodeTimingJson, I as hasRecorderDeviceChoice, J as recordedMediaKind, K as recorderBitsPerSecond, L as recorderDeviceGroups, N as recorderDeviceOptions, O as requestCameraStream, P as requestMicStream, Q as requestScreenStream, U as timingPathFor, V as useMediaDevices, W as useStreamPreview } from './recorder-B6MtQH5u.js';
|
|
30
|
+
import { R as RecorderState } from './useNarrationStage-D3Sgcf0L.js';
|
|
31
|
+
export { C as CanvasSink, a as CaptureKind, D as DEFAULT_TELEPROMPTER_PREFS, F as FloatOpenOptions, b as FloatTier, c as FloatingWindowHandle, d as FloatingWindowManager, M as MicAnalysisHandle, e as MicAnalysisStatus, N as NarrationRecorderController, f as NarrationRecorderState, g as NarrationStageHandle, h as NarrationTake, P as PrompterTransport, i as RecorderAudioBitrateMode, j as RecorderCameraLane, k as RecorderExtendedMediaOptions, l as RecorderSource, m as ResolvedFormat, T as TeleprompterController, n as TeleprompterPrefs, o as TeleprompterRecordingDeps, U as UseMediaRecorderOptions, p as UseMediaRecorderResult, q as UseNarrationStageOptions, r as buildFilename, s as createFloatingWindowManager, t as detectFloatTiers, u as getCaptureKind, v as resolveFormat, w as supportsDisplayMedia, x as supportsMediaRecorder, y as supportsUserMedia, z as useFloatingWindow, A as useMediaRecorder, B as useMicAnalysis, E as useNarrationRecorder, G as useNarrationStage, H as useTeleprompter, I as vadConfigForSensitivity } from './useNarrationStage-D3Sgcf0L.js';
|
|
32
32
|
export { EYE_LINE_FRACTION, NarrationSavePlan, NarrationSaveResult, NarrationStage, NarrationStageProps, PCM_WORKLET_NAME, PCM_WORKLET_SOURCE, TELEPROMPTER_CSS, TeleprompterControls, TeleprompterControlsProps, TeleprompterSurface, TeleprompterSurfaceProps, TeleprompterView, TeleprompterViewProps, TokenLineMap, buildNarrationSavePlan, cameraVideoLine, ensureTeleprompterStyles, executeNarrationSave, insertNarrationPreamble, measureTokenLines, narrationAnnotationLine, prompterVarsFromTheme, registerPcmWorklet, stepScroll, targetOffsetFor } from './teleprompter/index.js';
|
|
33
33
|
export { H as HarperProofingConfig, P as ProofingCapability, a as ProofingDocumentRef, b as ProofingIgnoreStore, c as ProofingLanguage, d as ProofingLintOptions, e as ProofingProvider, f as ProofingProviderFactory } from './types-B_aHRuSc.js';
|
|
34
34
|
export { createHarperProofingProvider } from './proofing/index.js';
|
package/dist/index.js
CHANGED
|
@@ -229,15 +229,15 @@ import {
|
|
|
229
229
|
useTreeViewData,
|
|
230
230
|
viewStateFromBinding,
|
|
231
231
|
writeHeadingViewState
|
|
232
|
-
} from "./chunk-
|
|
232
|
+
} from "./chunk-CDISORBP.js";
|
|
233
233
|
import "./chunk-V4NBQF5C.js";
|
|
234
234
|
import {
|
|
235
235
|
JsonEditor
|
|
236
|
-
} from "./chunk-
|
|
236
|
+
} from "./chunk-UYKOTWJM.js";
|
|
237
237
|
import {
|
|
238
238
|
markdownToTiptap,
|
|
239
239
|
tiptapToMarkdown
|
|
240
|
-
} from "./chunk-
|
|
240
|
+
} from "./chunk-ES6CPRCW.js";
|
|
241
241
|
import {
|
|
242
242
|
ImageEditor,
|
|
243
243
|
ImageViewer,
|
|
@@ -247,7 +247,7 @@ import {
|
|
|
247
247
|
} from "./chunk-V44VP242.js";
|
|
248
248
|
import {
|
|
249
249
|
RecorderButton
|
|
250
|
-
} from "./chunk-
|
|
250
|
+
} from "./chunk-DN6XFOY2.js";
|
|
251
251
|
import {
|
|
252
252
|
DEFAULT_RECORDER_DEVICE_SETTINGS,
|
|
253
253
|
RecorderDeviceQuickPicks,
|
|
@@ -278,11 +278,11 @@ import {
|
|
|
278
278
|
unshownSlidesWarning,
|
|
279
279
|
useMediaDevices,
|
|
280
280
|
useMediaRecorder
|
|
281
|
-
} from "./chunk-
|
|
281
|
+
} from "./chunk-BJ3TXAIQ.js";
|
|
282
282
|
import "./chunk-GS7QWYFT.js";
|
|
283
283
|
import {
|
|
284
284
|
TeleprompterView
|
|
285
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-ENDRPV6T.js";
|
|
286
286
|
import {
|
|
287
287
|
DEFAULT_TELEPROMPTER_PREFS,
|
|
288
288
|
EYE_LINE_FRACTION,
|
|
@@ -322,7 +322,7 @@ import {
|
|
|
322
322
|
useStreamPreview,
|
|
323
323
|
useTeleprompter,
|
|
324
324
|
vadConfigForSensitivity
|
|
325
|
-
} from "./chunk-
|
|
325
|
+
} from "./chunk-34FRFDQ6.js";
|
|
326
326
|
|
|
327
327
|
// src/FolderView.tsx
|
|
328
328
|
import { jsx, jsxs } from "react/jsx-runtime";
|
package/dist/recorder/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { C as CameraStreamOptions, D as DEFAULT_RECORDER_DEVICE_SETTINGS, M as MediaDeviceInventory, R as RecordedBookmark, a as RecordedMediaKind, b as RecorderAudioDeviceSettings, c as RecorderButton, d as RecorderButtonProps, e as RecorderCameraDeviceSettings, f as RecorderCameraSaveResult, g as RecorderColorScheme, h as RecorderConstraintMode, i as RecorderDeviceOption, j as RecorderDeviceQuickPicks, k as RecorderDeviceQuickPicksProps, l as RecorderDeviceSettings, m as RecorderDeviceSettingsPanel, n as RecorderDeviceSettingsPanelProps, o as RecorderEncodingSettings, p as RecorderModal, q as RecorderModalProps, s as RecorderPanel, t as RecorderPanelProps, u as RecorderSaveResult, v as RecorderScreenAudioSettings, w as RecorderScreenDeviceSettings, S as ScreenStreamHandle, y as ScreenStreamOptions, T as TimingJson, A as buildRecorderAudioConstraints, B as buildRecorderCameraConstraints, E as buildRecorderScreenAudioConstraints, F as buildRecorderScreenConstraints, G as buildTimingJson, H as encodeTimingJson, I as hasRecorderDeviceChoice, J as recordedMediaKind, K as recorderBitsPerSecond, L as recorderDeviceGroups, N as recorderDeviceOptions, O as requestCameraStream, P as requestMicStream, Q as requestScreenStream, U as timingPathFor, V as useMediaDevices, W as useStreamPreview } from '../recorder-
|
|
2
|
-
export { a as CaptureKind, i as RecorderAudioBitrateMode, j as RecorderCameraLane, k as RecorderExtendedMediaOptions, l as RecorderSource, R as RecorderState, m as ResolvedFormat, U as UseMediaRecorderOptions, p as UseMediaRecorderResult, r as buildFilename, u as getCaptureKind, v as resolveFormat, w as supportsDisplayMedia, x as supportsMediaRecorder, y as supportsUserMedia, A as useMediaRecorder } from '../useNarrationStage-
|
|
1
|
+
export { C as CameraStreamOptions, D as DEFAULT_RECORDER_DEVICE_SETTINGS, M as MediaDeviceInventory, R as RecordedBookmark, a as RecordedMediaKind, b as RecorderAudioDeviceSettings, c as RecorderButton, d as RecorderButtonProps, e as RecorderCameraDeviceSettings, f as RecorderCameraSaveResult, g as RecorderColorScheme, h as RecorderConstraintMode, i as RecorderDeviceOption, j as RecorderDeviceQuickPicks, k as RecorderDeviceQuickPicksProps, l as RecorderDeviceSettings, m as RecorderDeviceSettingsPanel, n as RecorderDeviceSettingsPanelProps, o as RecorderEncodingSettings, p as RecorderModal, q as RecorderModalProps, s as RecorderPanel, t as RecorderPanelProps, u as RecorderSaveResult, v as RecorderScreenAudioSettings, w as RecorderScreenDeviceSettings, S as ScreenStreamHandle, y as ScreenStreamOptions, T as TimingJson, A as buildRecorderAudioConstraints, B as buildRecorderCameraConstraints, E as buildRecorderScreenAudioConstraints, F as buildRecorderScreenConstraints, G as buildTimingJson, H as encodeTimingJson, I as hasRecorderDeviceChoice, J as recordedMediaKind, K as recorderBitsPerSecond, L as recorderDeviceGroups, N as recorderDeviceOptions, O as requestCameraStream, P as requestMicStream, Q as requestScreenStream, U as timingPathFor, V as useMediaDevices, W as useStreamPreview } from '../recorder-B6MtQH5u.js';
|
|
2
|
+
export { a as CaptureKind, i as RecorderAudioBitrateMode, j as RecorderCameraLane, k as RecorderExtendedMediaOptions, l as RecorderSource, R as RecorderState, m as ResolvedFormat, U as UseMediaRecorderOptions, p as UseMediaRecorderResult, r as buildFilename, u as getCaptureKind, v as resolveFormat, w as supportsDisplayMedia, x as supportsMediaRecorder, y as supportsUserMedia, A as useMediaRecorder } from '../useNarrationStage-D3Sgcf0L.js';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import '@bendyline/squisq/schemas';
|
|
5
5
|
import '@bendyline/squisq/storage';
|
package/dist/recorder/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RecorderButton
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-DN6XFOY2.js";
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_RECORDER_DEVICE_SETTINGS,
|
|
6
6
|
RecorderDeviceQuickPicks,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
requestScreenStream,
|
|
21
21
|
useMediaDevices,
|
|
22
22
|
useMediaRecorder
|
|
23
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-BJ3TXAIQ.js";
|
|
24
24
|
import "../chunk-GS7QWYFT.js";
|
|
25
25
|
import {
|
|
26
26
|
buildFilename,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
supportsUserMedia,
|
|
35
35
|
timingPathFor,
|
|
36
36
|
useStreamPreview
|
|
37
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-34FRFDQ6.js";
|
|
38
38
|
export {
|
|
39
39
|
DEFAULT_RECORDER_DEVICE_SETTINGS,
|
|
40
40
|
RecorderButton,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { Doc, Theme, ViewportConfig, MediaProvider } from '@bendyline/squisq/schemas';
|
|
3
3
|
import { ContentContainer } from '@bendyline/squisq/storage';
|
|
4
|
-
import { l as RecorderSource, o as TeleprompterRecordingDeps } from './useNarrationStage-
|
|
4
|
+
import { l as RecorderSource, o as TeleprompterRecordingDeps } from './useNarrationStage-D3Sgcf0L.js';
|
|
5
5
|
import { CSSProperties, RefObject } from 'react';
|
|
6
6
|
|
|
7
7
|
type RecordedMediaKind = 'audio' | 'video';
|
|
@@ -61,6 +61,8 @@ interface RecorderSlidesOptions {
|
|
|
61
61
|
captureTimings?: boolean;
|
|
62
62
|
}
|
|
63
63
|
interface RecorderModalProps {
|
|
64
|
+
/** Combined recording byte threshold. Defaults to 90 MiB; final chunks are retained. */
|
|
65
|
+
maxRecordingBytes?: number;
|
|
64
66
|
/** Required — recordings are written here. */
|
|
65
67
|
mediaProvider: MediaProvider;
|
|
66
68
|
/**
|
|
@@ -155,7 +157,7 @@ interface SlideTimingSaveResult {
|
|
|
155
157
|
/** Take length the block ranges were normalized against. */
|
|
156
158
|
durationSec: number;
|
|
157
159
|
}
|
|
158
|
-
declare function RecorderModal({ mediaProvider, container, initialMode, colorScheme, onClose, onSave, narration, slides, title, }: RecorderModalProps): react_jsx_runtime.JSX.Element;
|
|
160
|
+
declare function RecorderModal({ mediaProvider, container, initialMode, colorScheme, onClose, onSave, narration, slides, title, maxRecordingBytes, }: RecorderModalProps): react_jsx_runtime.JSX.Element;
|
|
159
161
|
|
|
160
162
|
interface RecorderButtonProps {
|
|
161
163
|
/** Where to write the resulting recording. Required. */
|
package/dist/shell/index.js
CHANGED
|
@@ -7,14 +7,14 @@ import {
|
|
|
7
7
|
WysiwygEditor,
|
|
8
8
|
useEditorContext,
|
|
9
9
|
useEditorContextMenuItems
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-CDISORBP.js";
|
|
11
11
|
import "../chunk-V4NBQF5C.js";
|
|
12
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-ES6CPRCW.js";
|
|
13
13
|
import "../chunk-V44VP242.js";
|
|
14
|
-
import "../chunk-
|
|
14
|
+
import "../chunk-BJ3TXAIQ.js";
|
|
15
15
|
import "../chunk-GS7QWYFT.js";
|
|
16
|
-
import "../chunk-
|
|
17
|
-
import "../chunk-
|
|
16
|
+
import "../chunk-ENDRPV6T.js";
|
|
17
|
+
import "../chunk-34FRFDQ6.js";
|
|
18
18
|
export {
|
|
19
19
|
EditorContextMenuProvider,
|
|
20
20
|
EditorProvider,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { Doc, Theme, MediaProvider } from '@bendyline/squisq/schemas';
|
|
3
3
|
import { ContentContainer } from '@bendyline/squisq/storage';
|
|
4
|
-
import { o as TeleprompterRecordingDeps, g as NarrationStageHandle, T as TeleprompterController, c as FloatingWindowHandle } from '../useNarrationStage-
|
|
5
|
-
export { C as CanvasSink, D as DEFAULT_TELEPROMPTER_PREFS, F as FloatOpenOptions, b as FloatTier, d as FloatingWindowManager, M as MicAnalysisHandle, e as MicAnalysisStatus, N as NarrationRecorderController, f as NarrationRecorderState, h as NarrationTake, P as PrompterTransport, J as TELEPROMPTER_PREF_LIMITS, n as TeleprompterPrefs, q as UseNarrationStageOptions, s as createFloatingWindowManager, t as detectFloatTiers, K as normalizeTeleprompterPrefs, z as useFloatingWindow, B as useMicAnalysis, E as useNarrationRecorder, G as useNarrationStage, H as useTeleprompter, I as vadConfigForSensitivity } from '../useNarrationStage-
|
|
4
|
+
import { o as TeleprompterRecordingDeps, g as NarrationStageHandle, T as TeleprompterController, c as FloatingWindowHandle } from '../useNarrationStage-D3Sgcf0L.js';
|
|
5
|
+
export { C as CanvasSink, D as DEFAULT_TELEPROMPTER_PREFS, F as FloatOpenOptions, b as FloatTier, d as FloatingWindowManager, M as MicAnalysisHandle, e as MicAnalysisStatus, N as NarrationRecorderController, f as NarrationRecorderState, h as NarrationTake, P as PrompterTransport, J as TELEPROMPTER_PREF_LIMITS, n as TeleprompterPrefs, q as UseNarrationStageOptions, s as createFloatingWindowManager, t as detectFloatTiers, K as normalizeTeleprompterPrefs, z as useFloatingWindow, B as useMicAnalysis, E as useNarrationRecorder, G as useNarrationStage, H as useTeleprompter, I as vadConfigForSensitivity } from '../useNarrationStage-D3Sgcf0L.js';
|
|
6
6
|
import { NarrationTimingJsonV3, NarrationScript, NarrationAlignment } from '@bendyline/squisq/narration';
|
|
7
7
|
import { ReactNode } from 'react';
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TeleprompterView
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-ENDRPV6T.js";
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_TELEPROMPTER_PREFS,
|
|
6
6
|
EYE_LINE_FRACTION,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
useNarrationStage,
|
|
32
32
|
useTeleprompter,
|
|
33
33
|
vadConfigForSensitivity
|
|
34
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-34FRFDQ6.js";
|
|
35
35
|
export {
|
|
36
36
|
DEFAULT_TELEPROMPTER_PREFS,
|
|
37
37
|
EYE_LINE_FRACTION,
|
|
@@ -110,6 +110,12 @@ interface RecorderCameraLane {
|
|
|
110
110
|
extension: string | null;
|
|
111
111
|
}
|
|
112
112
|
interface UseMediaRecorderOptions {
|
|
113
|
+
/**
|
|
114
|
+
* Combined byte threshold for automatically stopping every capture lane.
|
|
115
|
+
* Defaults to 90 MiB. Browser chunk delivery can be delayed, so the final
|
|
116
|
+
* blobs may exceed this threshold; all bytes are retained for recovery.
|
|
117
|
+
*/
|
|
118
|
+
maxRecordingBytes?: number;
|
|
113
119
|
/** Which capture pipeline to use (default: `'mic'`). */
|
|
114
120
|
source?: RecorderSource;
|
|
115
121
|
/**
|
|
@@ -171,6 +177,12 @@ interface UseMediaRecorderOptions {
|
|
|
171
177
|
includeMicrophone?: boolean;
|
|
172
178
|
}
|
|
173
179
|
interface UseMediaRecorderResult {
|
|
180
|
+
/** Bytes received across all capture lanes, including the final flush. */
|
|
181
|
+
recordedBytes: number;
|
|
182
|
+
/** Effective byte threshold for this recorder. */
|
|
183
|
+
maxRecordingBytes: number;
|
|
184
|
+
/** Whether the recorder automatically stopped after reaching its byte threshold. */
|
|
185
|
+
limitReached: boolean;
|
|
174
186
|
/** Current recorder state. */
|
|
175
187
|
state: RecorderState;
|
|
176
188
|
/** `MediaStream` acquired by `request()`; live during preview/recording and
|
|
@@ -492,6 +504,8 @@ interface UseNarrationRecorderOptions {
|
|
|
492
504
|
audioRecorderOptions?: NarrationMediaRecorderOptions;
|
|
493
505
|
/** MediaRecorder hints for the camera companion file. */
|
|
494
506
|
cameraRecorderOptions?: NarrationMediaRecorderOptions;
|
|
507
|
+
/** Combined audio/camera soft stop threshold; defaults to 90 MiB. Final chunks are retained. */
|
|
508
|
+
maxRecordingBytes?: number;
|
|
495
509
|
/** Fired when capture actually starts (View starts the prompter). */
|
|
496
510
|
onRecordingStart?: () => void;
|
|
497
511
|
onRecordingStop?: () => void;
|
|
@@ -499,6 +513,9 @@ interface UseNarrationRecorderOptions {
|
|
|
499
513
|
interface NarrationRecorderController {
|
|
500
514
|
state: NarrationRecorderState;
|
|
501
515
|
error: Error | null;
|
|
516
|
+
recordedBytes: number;
|
|
517
|
+
maxRecordingBytes: number;
|
|
518
|
+
limitReached: boolean;
|
|
502
519
|
withCamera: boolean;
|
|
503
520
|
setWithCamera: (on: boolean) => void;
|
|
504
521
|
/** Live camera stream for the self-view while recording. */
|
|
@@ -546,6 +563,8 @@ interface UseNarrationStageOptions {
|
|
|
546
563
|
micConstraints?: MediaTrackConstraints;
|
|
547
564
|
/** Constraints for the optional narration camera lane. */
|
|
548
565
|
cameraConstraints?: MediaTrackConstraints;
|
|
566
|
+
/** Combined narration audio/camera soft stop threshold, in bytes. */
|
|
567
|
+
maxRecordingBytes?: number;
|
|
549
568
|
/** MediaRecorder hints for the narration audio file. */
|
|
550
569
|
audioRecorderOptions?: NarrationMediaRecorderOptions;
|
|
551
570
|
/** MediaRecorder hints for the optional narration camera file. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bendyline/squisq-editor-react",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.4",
|
|
4
4
|
"description": "React editor shell with raw/WYSIWYG/preview modes for Squisq documents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bendyline",
|
|
@@ -94,12 +94,12 @@
|
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
96
|
"dependencies": {
|
|
97
|
-
"@bendyline/squisq": "2.11.
|
|
97
|
+
"@bendyline/squisq": "2.11.4",
|
|
98
98
|
"@bendyline/squisq-calc": "2.11.0",
|
|
99
|
-
"@bendyline/squisq-formats": "2.6.
|
|
100
|
-
"@bendyline/squisq-grid-react": "2.11.
|
|
101
|
-
"@bendyline/squisq-react": "2.11.
|
|
102
|
-
"@bendyline/squisq-video-react": "2.4.
|
|
99
|
+
"@bendyline/squisq-formats": "2.6.4",
|
|
100
|
+
"@bendyline/squisq-grid-react": "2.11.5",
|
|
101
|
+
"@bendyline/squisq-react": "2.11.4",
|
|
102
|
+
"@bendyline/squisq-video-react": "2.4.8",
|
|
103
103
|
"@fortawesome/fontawesome-free": "7.2.0",
|
|
104
104
|
"@tiptap/core": "2.27.2",
|
|
105
105
|
"@tiptap/extension-heading": "2.27.2",
|