@bendyline/squisq-editor-react 2.8.0 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +1 -0
- package/README.md +5 -0
- package/dist/{chunk-OWOKKZAU.js → chunk-IRPOMTYK.js} +4 -0
- package/dist/{chunk-V3J5S7X6.js → chunk-JNJ7XO5L.js} +617 -99
- package/dist/{chunk-YPRX32GY.js → chunk-JYPLPGYJ.js} +1 -1
- package/dist/chunk-SAKLIEOX.js +144 -0
- package/dist/{chunk-K2WJYVS4.js → chunk-TCLNRATG.js} +48 -13
- package/dist/{chunk-SUXRSZ4Y.js → chunk-TQPZ6VVM.js} +4749 -2783
- package/dist/{chunk-AZ5ME4XG.js → chunk-WCGDDZB6.js} +3 -1
- package/dist/{chunk-IQFPX2CE.js → chunk-ZZTB6BEQ.js} +1 -1
- package/dist/index.d.ts +150 -7
- package/dist/index.js +39 -9
- package/dist/json-editor/index.js +2 -2
- package/dist/proofing/index.d.ts +32 -0
- package/dist/proofing/index.js +10 -0
- package/dist/recorder/index.d.ts +2 -2
- package/dist/recorder/index.js +3 -3
- package/dist/{recorder-DFP0Dw4v.d.ts → recorder-GrEh4xE8.d.ts} +67 -7
- package/dist/shell/index.d.ts +3 -1
- package/dist/shell/index.js +5 -5
- package/dist/{shell-Bv6neeA6.d.ts → shell-Dlh-mkn9.d.ts} +59 -2
- package/dist/styles/index.css +477 -14
- package/dist/teleprompter/index.d.ts +2 -2
- package/dist/teleprompter/index.js +2 -2
- package/dist/types-B_aHRuSc.d.ts +156 -0
- package/dist/{useNarrationStage-Bk3mdW75.d.ts → useNarrationStage-B6r9Zlq-.d.ts} +11 -1
- package/package.json +16 -5
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
NarrationStage,
|
|
6
6
|
buildFilename,
|
|
7
7
|
buildTimingJson,
|
|
8
|
+
encodeNarrationTimingJson,
|
|
8
9
|
encodeTimingJson,
|
|
9
10
|
requestCameraStream,
|
|
10
11
|
requestMicStream,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
timingPathFor,
|
|
17
18
|
useNarrationStage,
|
|
18
19
|
useStreamPreview
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-IRPOMTYK.js";
|
|
20
21
|
|
|
21
22
|
// src/recorder/sources/screenStream.ts
|
|
22
23
|
function mixAudioTracks(streams) {
|
|
@@ -634,6 +635,11 @@ function useMediaRecorder(options = {}) {
|
|
|
634
635
|
}
|
|
635
636
|
}, 100);
|
|
636
637
|
}, [clearTicker, deactivateCapture, transition]);
|
|
638
|
+
const getElapsedMs = useCallback(() => {
|
|
639
|
+
if (stateRef.current !== "recording") return null;
|
|
640
|
+
const startedAt = startTimestampRef.current;
|
|
641
|
+
return startedAt === null ? null : Math.max(0, Date.now() - startedAt);
|
|
642
|
+
}, []);
|
|
637
643
|
const stop = useCallback(() => {
|
|
638
644
|
if (stopPromiseRef.current) return stopPromiseRef.current;
|
|
639
645
|
const rec = recorderRef.current;
|
|
@@ -707,6 +713,7 @@ function useMediaRecorder(options = {}) {
|
|
|
707
713
|
extension: format?.extension ?? null,
|
|
708
714
|
directory: format?.directory ?? null,
|
|
709
715
|
durationMs,
|
|
716
|
+
getElapsedMs,
|
|
710
717
|
error,
|
|
711
718
|
camera,
|
|
712
719
|
cameraOffsetSec,
|
|
@@ -1652,16 +1659,371 @@ function recordedMediaKind(source, stream, mimeType) {
|
|
|
1652
1659
|
return source === "mic" ? "audio" : "video";
|
|
1653
1660
|
}
|
|
1654
1661
|
|
|
1662
|
+
// src/recorder/slidesModePolicy.ts
|
|
1663
|
+
function isExpandedPanel(mode) {
|
|
1664
|
+
return mode !== "none";
|
|
1665
|
+
}
|
|
1666
|
+
function panelModeAfterToggle(current, target, checked) {
|
|
1667
|
+
if (checked) return target;
|
|
1668
|
+
return current === target ? "none" : current;
|
|
1669
|
+
}
|
|
1670
|
+
function clampSlideIndex(index, count) {
|
|
1671
|
+
if (count <= 0) return 0;
|
|
1672
|
+
if (!Number.isFinite(index)) return 0;
|
|
1673
|
+
return Math.min(count - 1, Math.max(0, Math.floor(index)));
|
|
1674
|
+
}
|
|
1675
|
+
function slideStepForKey(key) {
|
|
1676
|
+
switch (key) {
|
|
1677
|
+
case "ArrowRight":
|
|
1678
|
+
case "ArrowDown":
|
|
1679
|
+
case "PageDown":
|
|
1680
|
+
case " ":
|
|
1681
|
+
case "Spacebar":
|
|
1682
|
+
return 1;
|
|
1683
|
+
case "ArrowLeft":
|
|
1684
|
+
case "ArrowUp":
|
|
1685
|
+
case "PageUp":
|
|
1686
|
+
return -1;
|
|
1687
|
+
default:
|
|
1688
|
+
return 0;
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
function showSlideTimingCheckbox(options) {
|
|
1692
|
+
return options.slidesOn && options.captureTimings && options.recorderState === "stopped" && options.hasBlob;
|
|
1693
|
+
}
|
|
1694
|
+
function unshownSlidesWarning(total, unshown) {
|
|
1695
|
+
if (unshown <= 0 || total <= 0) return null;
|
|
1696
|
+
const noun = unshown === 1 ? "slide was" : "slides were";
|
|
1697
|
+
return `${unshown} of ${total} ${noun} never shown \u2014 they'll be skipped during playback.`;
|
|
1698
|
+
}
|
|
1699
|
+
var SLIDE_TIMING_CHECKBOX_LABEL = "Update block timings when I save this narration";
|
|
1700
|
+
|
|
1701
|
+
// src/buildPreviewDoc.ts
|
|
1702
|
+
import {
|
|
1703
|
+
buildPreviewDoc,
|
|
1704
|
+
documentTitleFromFileName
|
|
1705
|
+
} from "@bendyline/squisq/doc";
|
|
1706
|
+
|
|
1707
|
+
// src/recorder/slides/slideDeck.ts
|
|
1708
|
+
import {
|
|
1709
|
+
buildPreviewDoc as buildPreviewDoc2,
|
|
1710
|
+
flattenRenderableBlocks,
|
|
1711
|
+
getBlockBodyText,
|
|
1712
|
+
materializeBlockLayers as materializeBlockLayers2
|
|
1713
|
+
} from "@bendyline/squisq/doc";
|
|
1714
|
+
|
|
1715
|
+
// src/resolveBlockVisual.ts
|
|
1716
|
+
import { materializeBlockLayers } from "@bendyline/squisq/doc";
|
|
1717
|
+
function resolveBlockVisual(doc, block, theme, viewport) {
|
|
1718
|
+
try {
|
|
1719
|
+
const slide = buildPreviewDoc({ ...doc, blocks: [block] }).blocks[0];
|
|
1720
|
+
if (!slide) return null;
|
|
1721
|
+
const ctx = {
|
|
1722
|
+
blockIndex: 0,
|
|
1723
|
+
totalBlocks: 1,
|
|
1724
|
+
theme,
|
|
1725
|
+
viewport,
|
|
1726
|
+
customTemplates: doc.customTemplates
|
|
1727
|
+
};
|
|
1728
|
+
const { layers } = materializeBlockLayers(slide, ctx);
|
|
1729
|
+
return { ...slide, layers };
|
|
1730
|
+
} catch {
|
|
1731
|
+
return null;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
// src/recorder/slides/slideDeck.ts
|
|
1736
|
+
function buildRecorderSlideDeck(doc, theme, viewport) {
|
|
1737
|
+
const flat = flattenRenderableBlocks(doc.blocks);
|
|
1738
|
+
if (flat.length === 0) return [];
|
|
1739
|
+
let slidesById;
|
|
1740
|
+
try {
|
|
1741
|
+
const preview = buildPreviewDoc2(doc, { interleaveImages: false });
|
|
1742
|
+
slidesById = new Map(preview.blocks.map((slide) => [slide.id, slide]));
|
|
1743
|
+
} catch {
|
|
1744
|
+
slidesById = /* @__PURE__ */ new Map();
|
|
1745
|
+
}
|
|
1746
|
+
return flat.map((block, index) => {
|
|
1747
|
+
const heading = block.title?.trim() || `Slide ${index + 1}`;
|
|
1748
|
+
let bodyText = "";
|
|
1749
|
+
try {
|
|
1750
|
+
bodyText = getBlockBodyText(block);
|
|
1751
|
+
} catch {
|
|
1752
|
+
bodyText = "";
|
|
1753
|
+
}
|
|
1754
|
+
return {
|
|
1755
|
+
blockId: block.id,
|
|
1756
|
+
heading,
|
|
1757
|
+
bodyText,
|
|
1758
|
+
visual: resolveSlideVisual(
|
|
1759
|
+
doc,
|
|
1760
|
+
block,
|
|
1761
|
+
slidesById.get(block.id),
|
|
1762
|
+
theme,
|
|
1763
|
+
viewport,
|
|
1764
|
+
index,
|
|
1765
|
+
flat.length
|
|
1766
|
+
)
|
|
1767
|
+
};
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
function resolveSlideVisual(doc, block, slide, theme, viewport, index, totalBlocks) {
|
|
1771
|
+
if (slide) {
|
|
1772
|
+
try {
|
|
1773
|
+
const { layers } = materializeBlockLayers2(slide, {
|
|
1774
|
+
blockIndex: index,
|
|
1775
|
+
totalBlocks,
|
|
1776
|
+
theme,
|
|
1777
|
+
viewport,
|
|
1778
|
+
customTemplates: doc.customTemplates
|
|
1779
|
+
});
|
|
1780
|
+
return { ...slide, layers };
|
|
1781
|
+
} catch {
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
return resolveBlockVisual(doc, block, theme, viewport);
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// src/recorder/slides/RecorderSlidesPanel.tsx
|
|
1788
|
+
import { useCallback as useCallback3 } from "react";
|
|
1789
|
+
|
|
1790
|
+
// src/TimelineBlockPreview.tsx
|
|
1791
|
+
import { memo } from "react";
|
|
1792
|
+
import { VIEWPORT_PRESETS } from "@bendyline/squisq/schemas";
|
|
1793
|
+
import { BlockRenderer, MediaContext } from "@bendyline/squisq-react";
|
|
1794
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1795
|
+
var BlockThumbnail = memo(function BlockThumbnail2({
|
|
1796
|
+
visual,
|
|
1797
|
+
viewport = VIEWPORT_PRESETS.landscape,
|
|
1798
|
+
basePath = "/",
|
|
1799
|
+
mediaProvider = null
|
|
1800
|
+
}) {
|
|
1801
|
+
return /* @__PURE__ */ jsx3(MediaContext.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx3(BlockRenderer, { block: visual, blockTime: 0, basePath, viewport }) });
|
|
1802
|
+
});
|
|
1803
|
+
|
|
1804
|
+
// src/recorder/slides/RecorderSlidesPanel.tsx
|
|
1805
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1806
|
+
var rootStyle = {
|
|
1807
|
+
flex: "1 1 auto",
|
|
1808
|
+
minHeight: 0,
|
|
1809
|
+
minWidth: 0,
|
|
1810
|
+
display: "flex",
|
|
1811
|
+
flexDirection: "column",
|
|
1812
|
+
outline: "none",
|
|
1813
|
+
color: "var(--squisq-recorder-text)"
|
|
1814
|
+
};
|
|
1815
|
+
var headerStyle = {
|
|
1816
|
+
flex: "0 0 auto",
|
|
1817
|
+
display: "flex",
|
|
1818
|
+
alignItems: "center",
|
|
1819
|
+
gap: 12,
|
|
1820
|
+
padding: "8px 10px",
|
|
1821
|
+
borderBottom: "1px solid var(--squisq-recorder-border)"
|
|
1822
|
+
};
|
|
1823
|
+
var counterStyle = {
|
|
1824
|
+
fontSize: 13,
|
|
1825
|
+
fontWeight: 600,
|
|
1826
|
+
whiteSpace: "nowrap"
|
|
1827
|
+
};
|
|
1828
|
+
var dotsStyle = {
|
|
1829
|
+
flex: "1 1 auto",
|
|
1830
|
+
minWidth: 0,
|
|
1831
|
+
display: "flex",
|
|
1832
|
+
flexWrap: "wrap",
|
|
1833
|
+
alignItems: "center",
|
|
1834
|
+
gap: 3
|
|
1835
|
+
};
|
|
1836
|
+
var navButtonStyle = {
|
|
1837
|
+
padding: "4px 10px",
|
|
1838
|
+
fontSize: 13,
|
|
1839
|
+
fontFamily: "inherit",
|
|
1840
|
+
cursor: "pointer",
|
|
1841
|
+
background: "var(--squisq-recorder-input)",
|
|
1842
|
+
color: "var(--squisq-recorder-text)",
|
|
1843
|
+
border: "1px solid var(--squisq-recorder-border)",
|
|
1844
|
+
borderRadius: 0
|
|
1845
|
+
};
|
|
1846
|
+
var stageStyle = {
|
|
1847
|
+
flex: "1 1 auto",
|
|
1848
|
+
minHeight: 0,
|
|
1849
|
+
overflow: "hidden",
|
|
1850
|
+
display: "flex",
|
|
1851
|
+
alignItems: "center",
|
|
1852
|
+
justifyContent: "center",
|
|
1853
|
+
padding: 8,
|
|
1854
|
+
background: "var(--squisq-recorder-surface-muted)"
|
|
1855
|
+
};
|
|
1856
|
+
var notesStyle = {
|
|
1857
|
+
flex: "0 0 auto",
|
|
1858
|
+
maxHeight: "32%",
|
|
1859
|
+
minHeight: 0,
|
|
1860
|
+
overflowY: "auto",
|
|
1861
|
+
padding: "10px 12px",
|
|
1862
|
+
borderTop: "1px solid var(--squisq-recorder-border)",
|
|
1863
|
+
fontSize: 14,
|
|
1864
|
+
lineHeight: 1.5,
|
|
1865
|
+
whiteSpace: "pre-wrap"
|
|
1866
|
+
};
|
|
1867
|
+
var hintStyle = {
|
|
1868
|
+
margin: 0,
|
|
1869
|
+
fontSize: 12,
|
|
1870
|
+
color: "var(--squisq-recorder-muted)"
|
|
1871
|
+
};
|
|
1872
|
+
var headingStyle = {
|
|
1873
|
+
margin: "0 0 6px 0",
|
|
1874
|
+
fontSize: 13,
|
|
1875
|
+
fontWeight: 600
|
|
1876
|
+
};
|
|
1877
|
+
var SELF_HANDLING = /^(BUTTON|INPUT|TEXTAREA|SELECT|A)$/;
|
|
1878
|
+
function RecorderSlidesPanel({
|
|
1879
|
+
slides,
|
|
1880
|
+
index,
|
|
1881
|
+
onIndexChange,
|
|
1882
|
+
viewport,
|
|
1883
|
+
basePath = "/",
|
|
1884
|
+
mediaProvider = null,
|
|
1885
|
+
recording = false,
|
|
1886
|
+
shownBlockIds
|
|
1887
|
+
}) {
|
|
1888
|
+
const count = slides.length;
|
|
1889
|
+
const active = slides[clampSlideIndex(index, count)];
|
|
1890
|
+
const step = useCallback3(
|
|
1891
|
+
(delta) => onIndexChange(clampSlideIndex(index + delta, count)),
|
|
1892
|
+
[index, count, onIndexChange]
|
|
1893
|
+
);
|
|
1894
|
+
const handleKeyDown = useCallback3(
|
|
1895
|
+
(event) => {
|
|
1896
|
+
const delta = slideStepForKey(event.key);
|
|
1897
|
+
if (delta === 0) return;
|
|
1898
|
+
const target = event.target;
|
|
1899
|
+
if (target !== event.currentTarget && SELF_HANDLING.test(target.tagName)) return;
|
|
1900
|
+
event.preventDefault();
|
|
1901
|
+
step(delta);
|
|
1902
|
+
},
|
|
1903
|
+
[step]
|
|
1904
|
+
);
|
|
1905
|
+
if (count === 0 || !active) {
|
|
1906
|
+
return /* @__PURE__ */ jsx4("div", { style: { ...rootStyle, alignItems: "center", justifyContent: "center", padding: 24 }, children: /* @__PURE__ */ jsx4("p", { style: hintStyle, children: "This document has no slides yet." }) });
|
|
1907
|
+
}
|
|
1908
|
+
return /* @__PURE__ */ jsxs3(
|
|
1909
|
+
"div",
|
|
1910
|
+
{
|
|
1911
|
+
style: rootStyle,
|
|
1912
|
+
tabIndex: 0,
|
|
1913
|
+
onKeyDown: handleKeyDown,
|
|
1914
|
+
"data-testid": "recorder-slides-panel",
|
|
1915
|
+
"aria-label": "Slides",
|
|
1916
|
+
children: [
|
|
1917
|
+
/* @__PURE__ */ jsxs3("div", { style: headerStyle, children: [
|
|
1918
|
+
/* @__PURE__ */ jsxs3("span", { style: counterStyle, role: "status", children: [
|
|
1919
|
+
"Slide ",
|
|
1920
|
+
index + 1,
|
|
1921
|
+
" of ",
|
|
1922
|
+
count
|
|
1923
|
+
] }),
|
|
1924
|
+
/* @__PURE__ */ jsx4("span", { style: dotsStyle, "aria-hidden": "true", children: slides.map((slide, i) => /* @__PURE__ */ jsx4(
|
|
1925
|
+
"span",
|
|
1926
|
+
{
|
|
1927
|
+
style: {
|
|
1928
|
+
width: 6,
|
|
1929
|
+
height: 6,
|
|
1930
|
+
borderRadius: "50%",
|
|
1931
|
+
background: i === index ? "var(--squisq-recorder-accent)" : shownBlockIds?.has(slide.blockId) ? "var(--squisq-recorder-text)" : "var(--squisq-recorder-border)"
|
|
1932
|
+
}
|
|
1933
|
+
},
|
|
1934
|
+
slide.blockId
|
|
1935
|
+
)) }),
|
|
1936
|
+
/* @__PURE__ */ jsx4(
|
|
1937
|
+
"button",
|
|
1938
|
+
{
|
|
1939
|
+
type: "button",
|
|
1940
|
+
style: navButtonStyle,
|
|
1941
|
+
onClick: () => step(-1),
|
|
1942
|
+
disabled: index <= 0,
|
|
1943
|
+
"aria-label": "Previous slide",
|
|
1944
|
+
children: /* @__PURE__ */ jsx4(Icon, { icon: "fa-solid fa-chevron-left" })
|
|
1945
|
+
}
|
|
1946
|
+
),
|
|
1947
|
+
/* @__PURE__ */ jsx4(
|
|
1948
|
+
"button",
|
|
1949
|
+
{
|
|
1950
|
+
type: "button",
|
|
1951
|
+
style: navButtonStyle,
|
|
1952
|
+
onClick: () => step(1),
|
|
1953
|
+
disabled: index >= count - 1,
|
|
1954
|
+
"aria-label": "Next slide",
|
|
1955
|
+
children: /* @__PURE__ */ jsx4(Icon, { icon: "fa-solid fa-chevron-right" })
|
|
1956
|
+
}
|
|
1957
|
+
)
|
|
1958
|
+
] }),
|
|
1959
|
+
/* @__PURE__ */ jsx4("div", { style: stageStyle, children: /* @__PURE__ */ jsx4(
|
|
1960
|
+
"div",
|
|
1961
|
+
{
|
|
1962
|
+
style: {
|
|
1963
|
+
width: "100%",
|
|
1964
|
+
maxHeight: "100%",
|
|
1965
|
+
aspectRatio: `${viewport.width} / ${viewport.height}`,
|
|
1966
|
+
overflow: "hidden",
|
|
1967
|
+
background: "#000"
|
|
1968
|
+
},
|
|
1969
|
+
children: active.visual ? /* @__PURE__ */ jsx4(
|
|
1970
|
+
BlockThumbnail,
|
|
1971
|
+
{
|
|
1972
|
+
visual: active.visual,
|
|
1973
|
+
viewport,
|
|
1974
|
+
basePath,
|
|
1975
|
+
mediaProvider
|
|
1976
|
+
}
|
|
1977
|
+
) : /* @__PURE__ */ jsxs3(
|
|
1978
|
+
"div",
|
|
1979
|
+
{
|
|
1980
|
+
style: {
|
|
1981
|
+
width: "100%",
|
|
1982
|
+
height: "100%",
|
|
1983
|
+
display: "flex",
|
|
1984
|
+
alignItems: "center",
|
|
1985
|
+
justifyContent: "center",
|
|
1986
|
+
padding: 16,
|
|
1987
|
+
textAlign: "center",
|
|
1988
|
+
background: "var(--squisq-recorder-input)",
|
|
1989
|
+
color: "var(--squisq-recorder-muted)",
|
|
1990
|
+
fontSize: 13
|
|
1991
|
+
},
|
|
1992
|
+
children: [
|
|
1993
|
+
active.heading,
|
|
1994
|
+
" \u2014 no slide rendition"
|
|
1995
|
+
]
|
|
1996
|
+
}
|
|
1997
|
+
)
|
|
1998
|
+
}
|
|
1999
|
+
) }),
|
|
2000
|
+
/* @__PURE__ */ jsxs3("div", { style: notesStyle, "data-testid": "recorder-slide-notes", children: [
|
|
2001
|
+
/* @__PURE__ */ jsx4("p", { style: headingStyle, children: active.heading }),
|
|
2002
|
+
active.bodyText ? /* @__PURE__ */ jsx4("div", { children: active.bodyText }) : /* @__PURE__ */ jsx4("p", { style: hintStyle, children: "No additional narrative for this slide." }),
|
|
2003
|
+
/* @__PURE__ */ jsx4("p", { style: { ...hintStyle, marginTop: 8 }, children: recording ? "Recording \u2014 each slide is timed from when you first show it." : "Use the arrow keys or the buttons to move through the deck." })
|
|
2004
|
+
] })
|
|
2005
|
+
]
|
|
2006
|
+
}
|
|
2007
|
+
);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
1655
2010
|
// src/recorder/RecorderModal.tsx
|
|
1656
2011
|
import {
|
|
1657
2012
|
Fragment as Fragment2,
|
|
1658
|
-
useCallback as
|
|
2013
|
+
useCallback as useCallback4,
|
|
1659
2014
|
useEffect as useEffect4,
|
|
1660
2015
|
useId as useId2,
|
|
1661
2016
|
useMemo,
|
|
1662
2017
|
useRef as useRef2,
|
|
1663
2018
|
useState as useState3
|
|
1664
2019
|
} from "react";
|
|
2020
|
+
import { VIEWPORT_PRESETS as VIEWPORT_PRESETS2 } from "@bendyline/squisq/schemas";
|
|
2021
|
+
import {
|
|
2022
|
+
EMPTY_ADVANCE_LOG,
|
|
2023
|
+
advanceCoverage,
|
|
2024
|
+
buildAdvanceTimingJson,
|
|
2025
|
+
recordSlideShown
|
|
2026
|
+
} from "@bendyline/squisq/narration";
|
|
1665
2027
|
|
|
1666
2028
|
// src/modal/useModalDialog.ts
|
|
1667
2029
|
import { useModalDialog } from "@bendyline/squisq-react";
|
|
@@ -1689,7 +2051,7 @@ function narrationCaptureSummary(withCamera) {
|
|
|
1689
2051
|
}
|
|
1690
2052
|
|
|
1691
2053
|
// src/recorder/RecorderModal.tsx
|
|
1692
|
-
import { Fragment as Fragment3, jsx as
|
|
2054
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1693
2055
|
var overlayStyle = {
|
|
1694
2056
|
position: "fixed",
|
|
1695
2057
|
inset: 0,
|
|
@@ -2034,7 +2396,9 @@ function RecorderModal({
|
|
|
2034
2396
|
colorScheme = "light",
|
|
2035
2397
|
onClose,
|
|
2036
2398
|
onSave,
|
|
2037
|
-
narration = null
|
|
2399
|
+
narration = null,
|
|
2400
|
+
slides = null,
|
|
2401
|
+
title = "Record media"
|
|
2038
2402
|
}) {
|
|
2039
2403
|
const initialToggles = toggleStateFromMode(initialMode);
|
|
2040
2404
|
const [micOn, setMicOn] = useState3(initialToggles.micOn);
|
|
@@ -2048,7 +2412,10 @@ function RecorderModal({
|
|
|
2048
2412
|
const [playbackUrl, setPlaybackUrl] = useState3(null);
|
|
2049
2413
|
const [cameraPlaybackUrl, setCameraPlaybackUrl] = useState3(null);
|
|
2050
2414
|
const [playbackPositionMs, setPlaybackPositionMs] = useState3(0);
|
|
2051
|
-
const [
|
|
2415
|
+
const [panelMode, setPanelMode] = useState3("none");
|
|
2416
|
+
const narrationOn = panelMode === "narration";
|
|
2417
|
+
const slidesOn = panelMode === "slides";
|
|
2418
|
+
const expanded = isExpandedPanel(panelMode);
|
|
2052
2419
|
const [narrationRequesting, setNarrationRequesting] = useState3(false);
|
|
2053
2420
|
const [narrationPreview, setNarrationPreview] = useState3(null);
|
|
2054
2421
|
const [deviceSettings, setDeviceSettings] = useState3(() => ({
|
|
@@ -2131,7 +2498,43 @@ function RecorderModal({
|
|
|
2131
2498
|
});
|
|
2132
2499
|
const stageRef = useRef2(stage);
|
|
2133
2500
|
stageRef.current = stage;
|
|
2134
|
-
const
|
|
2501
|
+
const slidesViewport = slides?.viewport ?? VIEWPORT_PRESETS2.landscape;
|
|
2502
|
+
const slideDeck = useMemo(
|
|
2503
|
+
() => slides?.doc ? buildRecorderSlideDeck(slides.doc, slides.theme, slidesViewport) : [],
|
|
2504
|
+
[slides?.doc, slides?.theme, slidesViewport]
|
|
2505
|
+
);
|
|
2506
|
+
const slidesAvailable = slideDeck.length > 0;
|
|
2507
|
+
const slidesCaptureTimings = Boolean(slides?.captureTimings && slides?.doc);
|
|
2508
|
+
const [slideIndex, setSlideIndex] = useState3(0);
|
|
2509
|
+
const [advanceLog, setAdvanceLog] = useState3(EMPTY_ADVANCE_LOG);
|
|
2510
|
+
const [applySlideTimings, setApplySlideTimings] = useState3(true);
|
|
2511
|
+
const slideIndexRef = useRef2(slideIndex);
|
|
2512
|
+
slideIndexRef.current = slideIndex;
|
|
2513
|
+
const advanceLogRef = useRef2(advanceLog);
|
|
2514
|
+
advanceLogRef.current = advanceLog;
|
|
2515
|
+
const slideDeckRef = useRef2(slideDeck);
|
|
2516
|
+
slideDeckRef.current = slideDeck;
|
|
2517
|
+
const shownBlockIds = useMemo(
|
|
2518
|
+
() => new Set(advanceLog.map((advance) => advance.blockId)),
|
|
2519
|
+
[advanceLog]
|
|
2520
|
+
);
|
|
2521
|
+
const handleSlideIndexChange = useCallback4(
|
|
2522
|
+
(next) => {
|
|
2523
|
+
const clamped = clampSlideIndex(next, slideDeckRef.current.length);
|
|
2524
|
+
setSlideIndex(clamped);
|
|
2525
|
+
const elapsedMs = recorder.getElapsedMs();
|
|
2526
|
+
const blockId = slideDeckRef.current[clamped]?.blockId;
|
|
2527
|
+
if (elapsedMs === null || !blockId) return;
|
|
2528
|
+
setAdvanceLog((log) => recordSlideShown(log, blockId, elapsedMs));
|
|
2529
|
+
},
|
|
2530
|
+
[recorder]
|
|
2531
|
+
);
|
|
2532
|
+
const slideDeckKey = slideDeck.map((slide) => slide.blockId).join("\0");
|
|
2533
|
+
useEffect4(() => {
|
|
2534
|
+
setAdvanceLog(EMPTY_ADVANCE_LOG);
|
|
2535
|
+
setSlideIndex(0);
|
|
2536
|
+
}, [panelMode, slideDeckKey]);
|
|
2537
|
+
const handleDeviceSettingsChange = useCallback4(
|
|
2135
2538
|
(next) => {
|
|
2136
2539
|
setDeviceSettings(next);
|
|
2137
2540
|
if (narrationOn) {
|
|
@@ -2216,7 +2619,7 @@ function RecorderModal({
|
|
|
2216
2619
|
}
|
|
2217
2620
|
};
|
|
2218
2621
|
}, [cameraConstraints, narrationPreviewWanted]);
|
|
2219
|
-
const handleNarrationPreview =
|
|
2622
|
+
const handleNarrationPreview = useCallback4(async () => {
|
|
2220
2623
|
setNarrationRequesting(true);
|
|
2221
2624
|
try {
|
|
2222
2625
|
const controller = stageRef.current.controller;
|
|
@@ -2225,7 +2628,7 @@ function RecorderModal({
|
|
|
2225
2628
|
setNarrationRequesting(false);
|
|
2226
2629
|
}
|
|
2227
2630
|
}, []);
|
|
2228
|
-
const handleNarrationRecord =
|
|
2631
|
+
const handleNarrationRecord = useCallback4(() => {
|
|
2229
2632
|
void stageRef.current.recorder.start();
|
|
2230
2633
|
}, []);
|
|
2231
2634
|
const narrationCameraStream = narrationOn ? stage.recorder.cameraStream ?? narrationPreview : null;
|
|
@@ -2274,10 +2677,11 @@ function RecorderModal({
|
|
|
2274
2677
|
if (previousKeyRef.current !== captureKey) {
|
|
2275
2678
|
previousKeyRef.current = captureKey;
|
|
2276
2679
|
dualSaveProgressRef.current = {};
|
|
2680
|
+
setAdvanceLog(EMPTY_ADVANCE_LOG);
|
|
2277
2681
|
recorder.cancel();
|
|
2278
2682
|
}
|
|
2279
2683
|
}, [captureKey, recorder]);
|
|
2280
|
-
const handleClose =
|
|
2684
|
+
const handleClose = useCallback4(() => {
|
|
2281
2685
|
const s = stageRef.current;
|
|
2282
2686
|
if (closeNeedsConfirm(narrationOn, s.recorder.state, s.recorder.take !== null)) {
|
|
2283
2687
|
if (!window.confirm("Discard the current narration take?")) return;
|
|
@@ -2302,23 +2706,55 @@ function RecorderModal({
|
|
|
2302
2706
|
stage.controller.transport
|
|
2303
2707
|
)
|
|
2304
2708
|
});
|
|
2305
|
-
const handleRequest =
|
|
2709
|
+
const handleRequest = useCallback4(async () => {
|
|
2306
2710
|
setSaveError(null);
|
|
2307
2711
|
try {
|
|
2308
2712
|
await recorder.request();
|
|
2309
2713
|
} catch {
|
|
2310
2714
|
}
|
|
2311
2715
|
}, [recorder]);
|
|
2312
|
-
const handleStart =
|
|
2716
|
+
const handleStart = useCallback4(() => {
|
|
2313
2717
|
setSaveError(null);
|
|
2314
2718
|
dualSaveProgressRef.current = {};
|
|
2315
2719
|
recorder.start();
|
|
2720
|
+
const blockId = slideDeckRef.current[slideIndexRef.current]?.blockId;
|
|
2721
|
+
setAdvanceLog(blockId ? recordSlideShown(EMPTY_ADVANCE_LOG, blockId, 0) : EMPTY_ADVANCE_LOG);
|
|
2316
2722
|
}, [recorder]);
|
|
2317
|
-
const handleStop =
|
|
2723
|
+
const handleStop = useCallback4(async () => {
|
|
2318
2724
|
setSaveError(null);
|
|
2319
2725
|
await recorder.stop();
|
|
2320
2726
|
}, [recorder]);
|
|
2321
|
-
const
|
|
2727
|
+
const writeSlideTimingSidecar = useCallback4(
|
|
2728
|
+
async (mediaRelativePath, durationSec) => {
|
|
2729
|
+
const doc = slides?.doc;
|
|
2730
|
+
if (!slidesOn || !slidesCaptureTimings || !applySlideTimings || !doc) return null;
|
|
2731
|
+
const log = advanceLogRef.current;
|
|
2732
|
+
if (log.length === 0) return null;
|
|
2733
|
+
const timing = buildAdvanceTimingJson(doc, log, durationSec);
|
|
2734
|
+
const encoded = encodeNarrationTimingJson(timing);
|
|
2735
|
+
const sidecarPath = timingPathFor(mediaRelativePath);
|
|
2736
|
+
if (container) {
|
|
2737
|
+
await container.writeFile(sidecarPath, encoded, "application/json");
|
|
2738
|
+
} else {
|
|
2739
|
+
const written = await mediaProvider.addMedia(sidecarPath, encoded, "application/json");
|
|
2740
|
+
if (written !== sidecarPath) {
|
|
2741
|
+
console.warn(
|
|
2742
|
+
`[squisq-recorder] block timings were saved as "${written}" instead of "${sidecarPath}" \u2014 they will not be applied.`
|
|
2743
|
+
);
|
|
2744
|
+
return null;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
const coverage = advanceCoverage(doc, log);
|
|
2748
|
+
return {
|
|
2749
|
+
sidecarPath,
|
|
2750
|
+
blockCount: coverage.total,
|
|
2751
|
+
unshownCount: coverage.unshown,
|
|
2752
|
+
durationSec: timing.duration
|
|
2753
|
+
};
|
|
2754
|
+
},
|
|
2755
|
+
[slidesOn, slidesCaptureTimings, applySlideTimings, slides?.doc, container, mediaProvider]
|
|
2756
|
+
);
|
|
2757
|
+
const handleSave = useCallback4(async () => {
|
|
2322
2758
|
if (!recorder.blob || !recorder.mimeType || !recorder.extension || !recorder.directory) {
|
|
2323
2759
|
setSaveError("Nothing to save yet \u2014 record something first.");
|
|
2324
2760
|
return;
|
|
@@ -2365,6 +2801,8 @@ function RecorderModal({
|
|
|
2365
2801
|
);
|
|
2366
2802
|
progress.cameraPath = cameraPath;
|
|
2367
2803
|
const duration = recorder.durationMs / 1e3;
|
|
2804
|
+
const slideTiming = progress.slideTiming ?? await writeSlideTimingSidecar(screenPath, duration);
|
|
2805
|
+
progress.slideTiming = slideTiming;
|
|
2368
2806
|
const offsetSec = recorder.cameraOffsetSec ?? 0;
|
|
2369
2807
|
const result = {
|
|
2370
2808
|
relativePath: screenPath,
|
|
@@ -2373,7 +2811,8 @@ function RecorderModal({
|
|
|
2373
2811
|
mediaKind: "video",
|
|
2374
2812
|
mimeType: recorder.mimeType,
|
|
2375
2813
|
duration,
|
|
2376
|
-
hasTimingSidecar:
|
|
2814
|
+
hasTimingSidecar: slideTiming !== null,
|
|
2815
|
+
...slideTiming ? { slideTiming } : {},
|
|
2377
2816
|
camera: {
|
|
2378
2817
|
relativePath: cameraPath,
|
|
2379
2818
|
filename: cameraFilename,
|
|
@@ -2404,9 +2843,11 @@ function RecorderModal({
|
|
|
2404
2843
|
recorder.blob,
|
|
2405
2844
|
recorder.mimeType
|
|
2406
2845
|
);
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2846
|
+
const duration = recorder.durationMs / 1e3;
|
|
2847
|
+
const slideTiming = await writeSlideTimingSidecar(relativePath, duration);
|
|
2848
|
+
let hasTimingSidecar = slideTiming !== null;
|
|
2849
|
+
if (!slideTiming && source === "mic") {
|
|
2850
|
+
const timing = buildTimingJson(sourceText, duration);
|
|
2410
2851
|
const encoded = encodeTimingJson(timing);
|
|
2411
2852
|
const sidecarPath = timingPathFor(relativePath);
|
|
2412
2853
|
if (container) {
|
|
@@ -2428,11 +2869,12 @@ function RecorderModal({
|
|
|
2428
2869
|
source,
|
|
2429
2870
|
mediaKind,
|
|
2430
2871
|
mimeType: recorder.mimeType,
|
|
2431
|
-
duration
|
|
2872
|
+
duration,
|
|
2432
2873
|
hasTimingSidecar
|
|
2433
2874
|
};
|
|
2875
|
+
if (slideTiming) result.slideTiming = slideTiming;
|
|
2434
2876
|
if (source === "mic") {
|
|
2435
|
-
result.sourceText = sourceText;
|
|
2877
|
+
result.sourceText = slideTiming ? void 0 : sourceText;
|
|
2436
2878
|
}
|
|
2437
2879
|
onSave?.(result);
|
|
2438
2880
|
handleClose();
|
|
@@ -2454,13 +2896,15 @@ function RecorderModal({
|
|
|
2454
2896
|
mediaProvider,
|
|
2455
2897
|
container,
|
|
2456
2898
|
onSave,
|
|
2457
|
-
handleClose
|
|
2899
|
+
handleClose,
|
|
2900
|
+
writeSlideTimingSidecar
|
|
2458
2901
|
]);
|
|
2459
|
-
const handleDiscard =
|
|
2902
|
+
const handleDiscard = useCallback4(() => {
|
|
2460
2903
|
dualSaveProgressRef.current = {};
|
|
2904
|
+
setAdvanceLog(EMPTY_ADVANCE_LOG);
|
|
2461
2905
|
recorder.reset();
|
|
2462
2906
|
}, [recorder]);
|
|
2463
|
-
const handlePlaybackTimeUpdate =
|
|
2907
|
+
const handlePlaybackTimeUpdate = useCallback4(
|
|
2464
2908
|
(media) => {
|
|
2465
2909
|
const currentMs = Number.isFinite(media.currentTime) ? media.currentTime * 1e3 : 0;
|
|
2466
2910
|
setPlaybackPositionMs(Math.min(recorder.durationMs, Math.max(0, currentMs)));
|
|
@@ -2473,6 +2917,18 @@ function RecorderModal({
|
|
|
2473
2917
|
const canStop = recorder.state === "recording";
|
|
2474
2918
|
const canSave = recorder.state === "stopped" && recorder.blob !== null;
|
|
2475
2919
|
const isBusy = recorder.state === "requesting" || recorder.state === "stopping" || isSaving;
|
|
2920
|
+
const slidesTimingCapture = slidesOn && slidesCaptureTimings;
|
|
2921
|
+
const showTimingCheckbox = showSlideTimingCheckbox({
|
|
2922
|
+
slidesOn,
|
|
2923
|
+
captureTimings: slidesCaptureTimings,
|
|
2924
|
+
recorderState: recorder.state,
|
|
2925
|
+
hasBlob: recorder.blob !== null
|
|
2926
|
+
});
|
|
2927
|
+
const slideCoverage = useMemo(
|
|
2928
|
+
() => slides?.doc && showTimingCheckbox ? advanceCoverage(slides.doc, advanceLog) : null,
|
|
2929
|
+
[slides?.doc, showTimingCheckbox, advanceLog]
|
|
2930
|
+
);
|
|
2931
|
+
const slideCoverageWarning = slideCoverage ? unshownSlidesWarning(slideCoverage.total, slideCoverage.unshown) : null;
|
|
2476
2932
|
const togglesLocked = recorder.state === "recording" || recorder.state === "requesting" || canSave;
|
|
2477
2933
|
const toggleLockReason = canSave ? "Save or discard this recording before changing sources" : void 0;
|
|
2478
2934
|
const systemAudioHasCompanion = micOn || cameraOn || screenOn;
|
|
@@ -2542,22 +2998,24 @@ function RecorderModal({
|
|
|
2542
2998
|
};
|
|
2543
2999
|
}
|
|
2544
3000
|
};
|
|
2545
|
-
return /* @__PURE__ */
|
|
3001
|
+
return /* @__PURE__ */ jsx5(
|
|
2546
3002
|
"div",
|
|
2547
3003
|
{
|
|
2548
3004
|
ref: overlayRef,
|
|
2549
3005
|
className: "squisq-editor-shell squisq-recorder-overlay",
|
|
2550
3006
|
"data-theme": colorScheme,
|
|
2551
3007
|
style: { ...overlayStyle, ...recorderThemeStyle(colorScheme) },
|
|
2552
|
-
children: /* @__PURE__ */
|
|
3008
|
+
children: /* @__PURE__ */ jsxs4(
|
|
2553
3009
|
"div",
|
|
2554
3010
|
{
|
|
2555
3011
|
ref: dialogRef,
|
|
2556
3012
|
className: "squisq-editor-shell",
|
|
2557
3013
|
"data-theme": colorScheme,
|
|
2558
3014
|
"data-narration": narrationOn ? "true" : void 0,
|
|
3015
|
+
"data-slides": slidesOn ? "true" : void 0,
|
|
3016
|
+
"data-panel-mode": panelMode,
|
|
2559
3017
|
style: {
|
|
2560
|
-
...
|
|
3018
|
+
...expanded ? modalExpandedStyle : modalStyle,
|
|
2561
3019
|
...recorderThemeStyle(colorScheme)
|
|
2562
3020
|
},
|
|
2563
3021
|
onClick: (e) => e.stopPropagation(),
|
|
@@ -2566,15 +3024,15 @@ function RecorderModal({
|
|
|
2566
3024
|
"aria-labelledby": headingId,
|
|
2567
3025
|
tabIndex: -1,
|
|
2568
3026
|
children: [
|
|
2569
|
-
/* @__PURE__ */
|
|
2570
|
-
/* @__PURE__ */
|
|
2571
|
-
/* @__PURE__ */
|
|
2572
|
-
/* @__PURE__ */
|
|
2573
|
-
groupIndex > 0 && /* @__PURE__ */
|
|
2574
|
-
/* @__PURE__ */
|
|
3027
|
+
/* @__PURE__ */ jsx5("h2", { id: headingId, style: titleStyle, children: title }),
|
|
3028
|
+
/* @__PURE__ */ jsxs4("div", { style: expanded ? bodyRowStyle : void 0, children: [
|
|
3029
|
+
/* @__PURE__ */ jsxs4("div", { style: expanded ? leftColStyle : void 0, children: [
|
|
3030
|
+
/* @__PURE__ */ jsx5("div", { style: toggleRowStyle, role: "group", "aria-label": "Capture sources", children: TOGGLE_GROUPS.map((group, groupIndex) => /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3031
|
+
groupIndex > 0 && /* @__PURE__ */ jsx5("div", { "aria-hidden": "true", style: groupDividerStyle }),
|
|
3032
|
+
/* @__PURE__ */ jsx5("div", { style: toggleGroupStyle, children: group.toggles.map((t) => {
|
|
2575
3033
|
if (t.key === "systemAudio" && !canIncludeSystemAudio) return null;
|
|
2576
3034
|
const props = narrationOn ? narrationToggleFor(t.key) : simpleToggleProps(t.key);
|
|
2577
|
-
return /* @__PURE__ */
|
|
3035
|
+
return /* @__PURE__ */ jsx5(
|
|
2578
3036
|
"button",
|
|
2579
3037
|
{
|
|
2580
3038
|
type: "button",
|
|
@@ -2589,22 +3047,36 @@ function RecorderModal({
|
|
|
2589
3047
|
);
|
|
2590
3048
|
}) })
|
|
2591
3049
|
] }, group.label)) }),
|
|
2592
|
-
/* @__PURE__ */
|
|
2593
|
-
narrationAvailable && /* @__PURE__ */
|
|
2594
|
-
/* @__PURE__ */
|
|
3050
|
+
/* @__PURE__ */ jsx5("p", { style: summaryStyle, children: narrationOn ? narrationCaptureSummary(stage.recorder.withCamera) : captureSummary(micOn, cameraOn, screenOn, includeSystemAudio) }),
|
|
3051
|
+
narrationAvailable && /* @__PURE__ */ jsxs4("label", { style: checkboxRowStyle, children: [
|
|
3052
|
+
/* @__PURE__ */ jsx5(
|
|
2595
3053
|
"input",
|
|
2596
3054
|
{
|
|
2597
3055
|
type: "checkbox",
|
|
2598
3056
|
style: { accentColor: "var(--squisq-recorder-accent)" },
|
|
2599
3057
|
checked: narrationOn,
|
|
2600
|
-
onChange: (e) =>
|
|
3058
|
+
onChange: (e) => setPanelMode(panelModeAfterToggle(panelMode, "narration", e.target.checked)),
|
|
2601
3059
|
disabled: narrationToggleDisabled,
|
|
2602
3060
|
title: narrationToggleDisabled ? narrationOn ? "Finish or discard the narration take first" : "Save or discard this recording before switching modes" : void 0
|
|
2603
3061
|
}
|
|
2604
3062
|
),
|
|
2605
3063
|
"Show narration mode"
|
|
2606
3064
|
] }),
|
|
2607
|
-
/* @__PURE__ */
|
|
3065
|
+
slidesAvailable && /* @__PURE__ */ jsxs4("label", { style: checkboxRowStyle, children: [
|
|
3066
|
+
/* @__PURE__ */ jsx5(
|
|
3067
|
+
"input",
|
|
3068
|
+
{
|
|
3069
|
+
type: "checkbox",
|
|
3070
|
+
style: { accentColor: "var(--squisq-recorder-accent)" },
|
|
3071
|
+
checked: slidesOn,
|
|
3072
|
+
onChange: (e) => setPanelMode(panelModeAfterToggle(panelMode, "slides", e.target.checked)),
|
|
3073
|
+
disabled: narrationToggleDisabled,
|
|
3074
|
+
title: narrationToggleDisabled ? "Save or discard this recording before switching modes" : void 0
|
|
3075
|
+
}
|
|
3076
|
+
),
|
|
3077
|
+
"Show slides mode"
|
|
3078
|
+
] }),
|
|
3079
|
+
/* @__PURE__ */ jsx5(
|
|
2608
3080
|
RecorderDeviceQuickPicks,
|
|
2609
3081
|
{
|
|
2610
3082
|
devices: mediaDevices,
|
|
@@ -2623,7 +3095,7 @@ function RecorderModal({
|
|
|
2623
3095
|
disabled: deviceSettingsLocked
|
|
2624
3096
|
}
|
|
2625
3097
|
),
|
|
2626
|
-
/* @__PURE__ */
|
|
3098
|
+
/* @__PURE__ */ jsx5(
|
|
2627
3099
|
RecorderDeviceSettingsPanel,
|
|
2628
3100
|
{
|
|
2629
3101
|
value: deviceSettings,
|
|
@@ -2638,10 +3110,10 @@ function RecorderModal({
|
|
|
2638
3110
|
cameraStream: activeCameraStream
|
|
2639
3111
|
}
|
|
2640
3112
|
),
|
|
2641
|
-
!narrationOn && recorder.error && /* @__PURE__ */
|
|
2642
|
-
!narrationOn && saveError && /* @__PURE__ */
|
|
2643
|
-
narrationOn && (stage.recorder.error ?? stage.controller.mic.error) && /* @__PURE__ */
|
|
2644
|
-
narrationOn && narrationCameraStream && /* @__PURE__ */
|
|
3113
|
+
!narrationOn && recorder.error && /* @__PURE__ */ jsx5("div", { style: errorStyle, children: recorder.error.message }),
|
|
3114
|
+
!narrationOn && saveError && /* @__PURE__ */ jsx5("div", { style: errorStyle, children: saveError }),
|
|
3115
|
+
narrationOn && (stage.recorder.error ?? stage.controller.mic.error) && /* @__PURE__ */ jsx5("div", { style: errorStyle, children: (stage.recorder.error ?? stage.controller.mic.error)?.message }),
|
|
3116
|
+
narrationOn && narrationCameraStream && /* @__PURE__ */ jsx5("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx5(
|
|
2645
3117
|
"video",
|
|
2646
3118
|
{
|
|
2647
3119
|
ref: previewRef,
|
|
@@ -2651,10 +3123,10 @@ function RecorderModal({
|
|
|
2651
3123
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
2652
3124
|
}
|
|
2653
3125
|
) }),
|
|
2654
|
-
narrationOn && !narrationCameraStream && narrationTakeDone && /* @__PURE__ */
|
|
2655
|
-
narrationOn && !narrationCameraStream && !narrationTakeDone && stage.recorder.withCamera && /* @__PURE__ */
|
|
2656
|
-
narrationOn && !narrationCameraStream && !narrationTakeDone && !stage.recorder.withCamera && /* @__PURE__ */
|
|
2657
|
-
/* @__PURE__ */
|
|
3126
|
+
narrationOn && !narrationCameraStream && narrationTakeDone && /* @__PURE__ */ jsx5("div", { style: audioMeterStyle, children: stage.recorder.take ? `\u2713 Recorded ${formatDurationMs(stage.recorder.take.durationSec * 1e3)}` : "\u25CF Processing take\u2026" }),
|
|
3127
|
+
narrationOn && !narrationCameraStream && !narrationTakeDone && stage.recorder.withCamera && /* @__PURE__ */ jsx5("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx5("span", { children: narrationPreviewWanted ? "Camera starting\u2026" : "Click Start preview to turn on your camera." }) }),
|
|
3128
|
+
narrationOn && !narrationCameraStream && !narrationTakeDone && !stage.recorder.withCamera && /* @__PURE__ */ jsxs4("div", { style: { ...audioMeterStyle, position: "relative", overflow: "hidden" }, children: [
|
|
3129
|
+
/* @__PURE__ */ jsx5(
|
|
2658
3130
|
"div",
|
|
2659
3131
|
{
|
|
2660
3132
|
"aria-hidden": "true",
|
|
@@ -2664,11 +3136,11 @@ function RecorderModal({
|
|
|
2664
3136
|
}
|
|
2665
3137
|
}
|
|
2666
3138
|
),
|
|
2667
|
-
/* @__PURE__ */
|
|
3139
|
+
/* @__PURE__ */ jsx5("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." })
|
|
2668
3140
|
] }),
|
|
2669
|
-
!narrationOn && !showPreview && /* @__PURE__ */
|
|
2670
|
-
!narrationOn && showPreview && recorder.state !== "stopped" && !isAudioOnly && /* @__PURE__ */
|
|
2671
|
-
/* @__PURE__ */
|
|
3141
|
+
!narrationOn && !showPreview && /* @__PURE__ */ jsx5("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx5("span", { children: "Click Start Preview to start a recording." }) }),
|
|
3142
|
+
!narrationOn && showPreview && recorder.state !== "stopped" && !isAudioOnly && /* @__PURE__ */ jsxs4("div", { style: isDual ? { ...previewBoxStyle, position: "relative" } : previewBoxStyle, children: [
|
|
3143
|
+
/* @__PURE__ */ jsx5(
|
|
2672
3144
|
"video",
|
|
2673
3145
|
{
|
|
2674
3146
|
ref: previewRef,
|
|
@@ -2678,7 +3150,7 @@ function RecorderModal({
|
|
|
2678
3150
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
2679
3151
|
}
|
|
2680
3152
|
),
|
|
2681
|
-
isDual && /* @__PURE__ */
|
|
3153
|
+
isDual && /* @__PURE__ */ jsx5(
|
|
2682
3154
|
"video",
|
|
2683
3155
|
{
|
|
2684
3156
|
ref: cameraPreviewRef,
|
|
@@ -2699,12 +3171,12 @@ function RecorderModal({
|
|
|
2699
3171
|
}
|
|
2700
3172
|
)
|
|
2701
3173
|
] }),
|
|
2702
|
-
!narrationOn && showPreview && recorder.state !== "stopped" && isAudioOnly && /* @__PURE__ */
|
|
3174
|
+
!narrationOn && showPreview && recorder.state !== "stopped" && isAudioOnly && /* @__PURE__ */ jsx5("div", { style: audioMeterStyle, children: recorder.state === "recording" ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
2703
3175
|
"\u25CF Recording ",
|
|
2704
3176
|
formatDurationMs(recorder.durationMs)
|
|
2705
|
-
] }) : /* @__PURE__ */
|
|
2706
|
-
!narrationOn && recorder.state === "stopped" && playbackUrl && !isAudioOnly && /* @__PURE__ */
|
|
2707
|
-
/* @__PURE__ */
|
|
3177
|
+
] }) : /* @__PURE__ */ jsx5(Fragment3, { children: "Microphone ready" }) }),
|
|
3178
|
+
!narrationOn && recorder.state === "stopped" && playbackUrl && !isAudioOnly && /* @__PURE__ */ jsxs4("div", { style: { ...previewBoxStyle, position: "relative" }, children: [
|
|
3179
|
+
/* @__PURE__ */ jsx5(
|
|
2708
3180
|
"video",
|
|
2709
3181
|
{
|
|
2710
3182
|
src: playbackUrl,
|
|
@@ -2716,7 +3188,7 @@ function RecorderModal({
|
|
|
2716
3188
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
2717
3189
|
}
|
|
2718
3190
|
),
|
|
2719
|
-
/* @__PURE__ */
|
|
3191
|
+
/* @__PURE__ */ jsxs4(
|
|
2720
3192
|
"div",
|
|
2721
3193
|
{
|
|
2722
3194
|
role: "timer",
|
|
@@ -2730,9 +3202,9 @@ function RecorderModal({
|
|
|
2730
3202
|
}
|
|
2731
3203
|
)
|
|
2732
3204
|
] }),
|
|
2733
|
-
!narrationOn && recorder.state === "stopped" && isDual && cameraPlaybackUrl && /* @__PURE__ */
|
|
2734
|
-
/* @__PURE__ */
|
|
2735
|
-
/* @__PURE__ */
|
|
3205
|
+
!narrationOn && recorder.state === "stopped" && isDual && cameraPlaybackUrl && /* @__PURE__ */ jsxs4("div", { style: { marginBottom: 12 }, children: [
|
|
3206
|
+
/* @__PURE__ */ jsx5("div", { style: summaryStyle, children: "Camera (picture-in-picture)" }),
|
|
3207
|
+
/* @__PURE__ */ jsx5(
|
|
2736
3208
|
"video",
|
|
2737
3209
|
{
|
|
2738
3210
|
src: cameraPlaybackUrl,
|
|
@@ -2748,16 +3220,16 @@ function RecorderModal({
|
|
|
2748
3220
|
}
|
|
2749
3221
|
)
|
|
2750
3222
|
] }),
|
|
2751
|
-
!narrationOn && recorder.state === "stopped" && playbackUrl && isAudioOnly && /* @__PURE__ */
|
|
2752
|
-
/* @__PURE__ */
|
|
3223
|
+
!narrationOn && recorder.state === "stopped" && playbackUrl && isAudioOnly && /* @__PURE__ */ jsxs4("div", { style: { marginBottom: 12 }, children: [
|
|
3224
|
+
/* @__PURE__ */ jsxs4("div", { style: { ...audioMeterStyle, marginBottom: 8 }, children: [
|
|
2753
3225
|
"\u2713 Recorded ",
|
|
2754
3226
|
formatDurationMs(recorder.durationMs)
|
|
2755
3227
|
] }),
|
|
2756
|
-
/* @__PURE__ */
|
|
3228
|
+
/* @__PURE__ */ jsx5("audio", { src: playbackUrl, controls: true, style: { width: "100%" } })
|
|
2757
3229
|
] }),
|
|
2758
|
-
!narrationOn && source === "mic" && /* @__PURE__ */
|
|
2759
|
-
/* @__PURE__ */
|
|
2760
|
-
/* @__PURE__ */
|
|
3230
|
+
!narrationOn && !slidesTimingCapture && source === "mic" && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3231
|
+
/* @__PURE__ */ jsx5("label", { style: labelStyle, htmlFor: "recorder-source-text", children: "Script (used to auto-match this narration to a block)" }),
|
|
3232
|
+
/* @__PURE__ */ jsx5(
|
|
2761
3233
|
"textarea",
|
|
2762
3234
|
{
|
|
2763
3235
|
id: "recorder-source-text",
|
|
@@ -2769,8 +3241,8 @@ function RecorderModal({
|
|
|
2769
3241
|
}
|
|
2770
3242
|
)
|
|
2771
3243
|
] }),
|
|
2772
|
-
/* @__PURE__ */
|
|
2773
|
-
/* @__PURE__ */
|
|
3244
|
+
/* @__PURE__ */ jsx5("label", { style: labelStyle, htmlFor: "recorder-basename", children: "Filename (optional)" }),
|
|
3245
|
+
/* @__PURE__ */ jsx5(
|
|
2774
3246
|
"input",
|
|
2775
3247
|
{
|
|
2776
3248
|
id: "recorder-basename",
|
|
@@ -2782,12 +3254,28 @@ function RecorderModal({
|
|
|
2782
3254
|
disabled: narrationOn ? !narrationRecorderIdle : recorder.state === "recording"
|
|
2783
3255
|
}
|
|
2784
3256
|
),
|
|
2785
|
-
!narrationOn && recorder.state === "recording" && !isAudioOnly && /* @__PURE__ */
|
|
3257
|
+
!narrationOn && recorder.state === "recording" && !isAudioOnly && /* @__PURE__ */ jsxs4("div", { style: recordingStatusStyle, children: [
|
|
2786
3258
|
"\u25CF Recording ",
|
|
2787
3259
|
formatDurationMs(recorder.durationMs)
|
|
2788
3260
|
] }),
|
|
2789
|
-
/* @__PURE__ */
|
|
2790
|
-
/* @__PURE__ */
|
|
3261
|
+
showTimingCheckbox && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3262
|
+
/* @__PURE__ */ jsxs4("label", { style: checkboxRowStyle, children: [
|
|
3263
|
+
/* @__PURE__ */ jsx5(
|
|
3264
|
+
"input",
|
|
3265
|
+
{
|
|
3266
|
+
type: "checkbox",
|
|
3267
|
+
style: { accentColor: "var(--squisq-recorder-accent)" },
|
|
3268
|
+
checked: applySlideTimings,
|
|
3269
|
+
onChange: (e) => setApplySlideTimings(e.target.checked),
|
|
3270
|
+
disabled: isSaving
|
|
3271
|
+
}
|
|
3272
|
+
),
|
|
3273
|
+
SLIDE_TIMING_CHECKBOX_LABEL
|
|
3274
|
+
] }),
|
|
3275
|
+
applySlideTimings && slideCoverageWarning && /* @__PURE__ */ jsx5("p", { style: summaryStyle, children: slideCoverageWarning })
|
|
3276
|
+
] }),
|
|
3277
|
+
/* @__PURE__ */ jsxs4("div", { style: buttonRowStyle, children: [
|
|
3278
|
+
/* @__PURE__ */ jsx5(
|
|
2791
3279
|
"button",
|
|
2792
3280
|
{
|
|
2793
3281
|
type: "button",
|
|
@@ -2797,8 +3285,8 @@ function RecorderModal({
|
|
|
2797
3285
|
children: "Close"
|
|
2798
3286
|
}
|
|
2799
3287
|
),
|
|
2800
|
-
narrationOn && /* @__PURE__ */
|
|
2801
|
-
narrationRecorderIdle && !narrationMicLive && /* @__PURE__ */
|
|
3288
|
+
narrationOn && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3289
|
+
narrationRecorderIdle && !narrationMicLive && /* @__PURE__ */ jsx5(
|
|
2802
3290
|
"button",
|
|
2803
3291
|
{
|
|
2804
3292
|
type: "button",
|
|
@@ -2808,14 +3296,14 @@ function RecorderModal({
|
|
|
2808
3296
|
children: narrationRequesting ? "Requesting\u2026" : "Start preview"
|
|
2809
3297
|
}
|
|
2810
3298
|
),
|
|
2811
|
-
narrationRecorderIdle && narrationMicLive && /* @__PURE__ */
|
|
2812
|
-
/* @__PURE__ */
|
|
3299
|
+
narrationRecorderIdle && narrationMicLive && /* @__PURE__ */ jsxs4("button", { type: "button", style: btnRecord, onClick: handleNarrationRecord, children: [
|
|
3300
|
+
/* @__PURE__ */ jsx5(
|
|
2813
3301
|
"span",
|
|
2814
3302
|
{
|
|
2815
3303
|
className: "squisq-recorder-record-dot",
|
|
2816
3304
|
style: recordDotFrameStyle,
|
|
2817
3305
|
"aria-hidden": "true",
|
|
2818
|
-
children: /* @__PURE__ */
|
|
3306
|
+
children: /* @__PURE__ */ jsx5(
|
|
2819
3307
|
"span",
|
|
2820
3308
|
{
|
|
2821
3309
|
className: "squisq-recorder-record-dot-center",
|
|
@@ -2826,7 +3314,7 @@ function RecorderModal({
|
|
|
2826
3314
|
),
|
|
2827
3315
|
"Record"
|
|
2828
3316
|
] }),
|
|
2829
|
-
(stage.recorder.state === "recording" || stage.recorder.state === "starting") && /* @__PURE__ */
|
|
3317
|
+
(stage.recorder.state === "recording" || stage.recorder.state === "starting") && /* @__PURE__ */ jsx5(
|
|
2830
3318
|
"button",
|
|
2831
3319
|
{
|
|
2832
3320
|
type: "button",
|
|
@@ -2835,11 +3323,11 @@ function RecorderModal({
|
|
|
2835
3323
|
children: "Stop"
|
|
2836
3324
|
}
|
|
2837
3325
|
),
|
|
2838
|
-
stage.recorder.state === "processing" && /* @__PURE__ */
|
|
2839
|
-
stage.recorder.state === "saving" && /* @__PURE__ */
|
|
2840
|
-
stage.recorder.state === "review" && stage.recorder.take && /* @__PURE__ */
|
|
2841
|
-
/* @__PURE__ */
|
|
2842
|
-
/* @__PURE__ */
|
|
3326
|
+
stage.recorder.state === "processing" && /* @__PURE__ */ jsx5("span", { style: recordingStatusStyle, children: "Aligning take\u2026" }),
|
|
3327
|
+
stage.recorder.state === "saving" && /* @__PURE__ */ jsx5("span", { style: recordingStatusStyle, children: "Saving\u2026" }),
|
|
3328
|
+
stage.recorder.state === "review" && stage.recorder.take && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3329
|
+
/* @__PURE__ */ jsx5("button", { type: "button", style: btnSecondary, onClick: stage.handleRetake, children: "Discard & re-record" }),
|
|
3330
|
+
/* @__PURE__ */ jsx5(
|
|
2843
3331
|
"button",
|
|
2844
3332
|
{
|
|
2845
3333
|
type: "button",
|
|
@@ -2850,8 +3338,8 @@ function RecorderModal({
|
|
|
2850
3338
|
)
|
|
2851
3339
|
] })
|
|
2852
3340
|
] }),
|
|
2853
|
-
!narrationOn && /* @__PURE__ */
|
|
2854
|
-
(recorder.state === "idle" || recorder.state === "error" || recorder.state === "requesting") && /* @__PURE__ */
|
|
3341
|
+
!narrationOn && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3342
|
+
(recorder.state === "idle" || recorder.state === "error" || recorder.state === "requesting") && /* @__PURE__ */ jsx5(
|
|
2855
3343
|
"button",
|
|
2856
3344
|
{
|
|
2857
3345
|
type: "button",
|
|
@@ -2861,14 +3349,14 @@ function RecorderModal({
|
|
|
2861
3349
|
children: recorder.state === "requesting" ? "Requesting\u2026" : "Start preview"
|
|
2862
3350
|
}
|
|
2863
3351
|
),
|
|
2864
|
-
canRecord && /* @__PURE__ */
|
|
2865
|
-
/* @__PURE__ */
|
|
3352
|
+
canRecord && /* @__PURE__ */ jsxs4("button", { type: "button", style: btnRecord, onClick: handleStart, disabled: isBusy, children: [
|
|
3353
|
+
/* @__PURE__ */ jsx5(
|
|
2866
3354
|
"span",
|
|
2867
3355
|
{
|
|
2868
3356
|
className: "squisq-recorder-record-dot",
|
|
2869
3357
|
style: recordDotFrameStyle,
|
|
2870
3358
|
"aria-hidden": "true",
|
|
2871
|
-
children: /* @__PURE__ */
|
|
3359
|
+
children: /* @__PURE__ */ jsx5(
|
|
2872
3360
|
"span",
|
|
2873
3361
|
{
|
|
2874
3362
|
className: "squisq-recorder-record-dot-center",
|
|
@@ -2879,9 +3367,9 @@ function RecorderModal({
|
|
|
2879
3367
|
),
|
|
2880
3368
|
"Record"
|
|
2881
3369
|
] }),
|
|
2882
|
-
canStop && /* @__PURE__ */
|
|
2883
|
-
canSave && /* @__PURE__ */
|
|
2884
|
-
/* @__PURE__ */
|
|
3370
|
+
canStop && /* @__PURE__ */ jsx5("button", { type: "button", style: btnDanger, onClick: handleStop, disabled: isBusy, children: "Stop" }),
|
|
3371
|
+
canSave && /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
3372
|
+
/* @__PURE__ */ jsx5(
|
|
2885
3373
|
"button",
|
|
2886
3374
|
{
|
|
2887
3375
|
type: "button",
|
|
@@ -2891,7 +3379,7 @@ function RecorderModal({
|
|
|
2891
3379
|
children: "Discard & re-record"
|
|
2892
3380
|
}
|
|
2893
3381
|
),
|
|
2894
|
-
/* @__PURE__ */
|
|
3382
|
+
/* @__PURE__ */ jsx5(
|
|
2895
3383
|
"button",
|
|
2896
3384
|
{
|
|
2897
3385
|
type: "button",
|
|
@@ -2905,7 +3393,7 @@ function RecorderModal({
|
|
|
2905
3393
|
] })
|
|
2906
3394
|
] })
|
|
2907
3395
|
] }),
|
|
2908
|
-
narrationOn && narration && /* @__PURE__ */
|
|
3396
|
+
narrationOn && narration && /* @__PURE__ */ jsx5("div", { style: rightColStyle, children: /* @__PURE__ */ jsx5(
|
|
2909
3397
|
NarrationStage,
|
|
2910
3398
|
{
|
|
2911
3399
|
stage,
|
|
@@ -2916,6 +3404,19 @@ function RecorderModal({
|
|
|
2916
3404
|
showTransportPlay: false,
|
|
2917
3405
|
showReviewActions: false
|
|
2918
3406
|
}
|
|
3407
|
+
) }),
|
|
3408
|
+
slidesOn && /* @__PURE__ */ jsx5("div", { style: rightColStyle, children: /* @__PURE__ */ jsx5(
|
|
3409
|
+
RecorderSlidesPanel,
|
|
3410
|
+
{
|
|
3411
|
+
slides: slideDeck,
|
|
3412
|
+
index: slideIndex,
|
|
3413
|
+
onIndexChange: handleSlideIndexChange,
|
|
3414
|
+
viewport: slidesViewport,
|
|
3415
|
+
basePath: slides?.basePath,
|
|
3416
|
+
mediaProvider: slides?.mediaProvider ?? mediaProvider,
|
|
3417
|
+
recording: recorder.state === "recording",
|
|
3418
|
+
shownBlockIds
|
|
3419
|
+
}
|
|
2919
3420
|
) })
|
|
2920
3421
|
] })
|
|
2921
3422
|
]
|
|
@@ -2926,9 +3427,9 @@ function RecorderModal({
|
|
|
2926
3427
|
}
|
|
2927
3428
|
|
|
2928
3429
|
// src/recorder/RecorderPanel.tsx
|
|
2929
|
-
import { useCallback as
|
|
3430
|
+
import { useCallback as useCallback5, useState as useState4 } from "react";
|
|
2930
3431
|
import { createPortal } from "react-dom";
|
|
2931
|
-
import { Fragment as Fragment4, jsx as
|
|
3432
|
+
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2932
3433
|
function RecorderPanel({
|
|
2933
3434
|
mediaProvider,
|
|
2934
3435
|
container = null,
|
|
@@ -2936,7 +3437,9 @@ function RecorderPanel({
|
|
|
2936
3437
|
colorScheme = "light",
|
|
2937
3438
|
onSave,
|
|
2938
3439
|
narration = null,
|
|
3440
|
+
slides = null,
|
|
2939
3441
|
tooltip = "Record media",
|
|
3442
|
+
title,
|
|
2940
3443
|
className,
|
|
2941
3444
|
open: controlledOpen,
|
|
2942
3445
|
onOpenChange,
|
|
@@ -2944,16 +3447,16 @@ function RecorderPanel({
|
|
|
2944
3447
|
}) {
|
|
2945
3448
|
const [uncontrolledOpen, setUncontrolledOpen] = useState4(false);
|
|
2946
3449
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
2947
|
-
const setOpen =
|
|
3450
|
+
const setOpen = useCallback5(
|
|
2948
3451
|
(nextOpen) => {
|
|
2949
3452
|
if (controlledOpen === void 0) setUncontrolledOpen(nextOpen);
|
|
2950
3453
|
onOpenChange?.(nextOpen);
|
|
2951
3454
|
},
|
|
2952
3455
|
[controlledOpen, onOpenChange]
|
|
2953
3456
|
);
|
|
2954
|
-
const handleClose =
|
|
2955
|
-
return /* @__PURE__ */
|
|
2956
|
-
showTrigger && /* @__PURE__ */
|
|
3457
|
+
const handleClose = useCallback5(() => setOpen(false), [setOpen]);
|
|
3458
|
+
return /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
3459
|
+
showTrigger && /* @__PURE__ */ jsx6(
|
|
2957
3460
|
"button",
|
|
2958
3461
|
{
|
|
2959
3462
|
type: "button",
|
|
@@ -2962,11 +3465,11 @@ function RecorderPanel({
|
|
|
2962
3465
|
"aria-label": tooltip,
|
|
2963
3466
|
"aria-expanded": open,
|
|
2964
3467
|
onClick: () => setOpen(!open),
|
|
2965
|
-
children: /* @__PURE__ */
|
|
3468
|
+
children: /* @__PURE__ */ jsx6(Icon, { icon: "fa-solid fa-microphone" })
|
|
2966
3469
|
}
|
|
2967
3470
|
),
|
|
2968
3471
|
open && typeof document !== "undefined" && createPortal(
|
|
2969
|
-
/* @__PURE__ */
|
|
3472
|
+
/* @__PURE__ */ jsx6(
|
|
2970
3473
|
RecorderModal,
|
|
2971
3474
|
{
|
|
2972
3475
|
mediaProvider,
|
|
@@ -2974,6 +3477,8 @@ function RecorderPanel({
|
|
|
2974
3477
|
initialMode,
|
|
2975
3478
|
colorScheme,
|
|
2976
3479
|
narration,
|
|
3480
|
+
slides,
|
|
3481
|
+
...title !== void 0 ? { title } : {},
|
|
2977
3482
|
onClose: handleClose,
|
|
2978
3483
|
onSave: (result) => {
|
|
2979
3484
|
onSave?.(result);
|
|
@@ -3002,6 +3507,19 @@ export {
|
|
|
3002
3507
|
buildRecorderScreenAudioConstraints,
|
|
3003
3508
|
recorderBitsPerSecond,
|
|
3004
3509
|
recordedMediaKind,
|
|
3510
|
+
isExpandedPanel,
|
|
3511
|
+
panelModeAfterToggle,
|
|
3512
|
+
clampSlideIndex,
|
|
3513
|
+
slideStepForKey,
|
|
3514
|
+
showSlideTimingCheckbox,
|
|
3515
|
+
unshownSlidesWarning,
|
|
3516
|
+
SLIDE_TIMING_CHECKBOX_LABEL,
|
|
3517
|
+
buildPreviewDoc,
|
|
3518
|
+
documentTitleFromFileName,
|
|
3519
|
+
resolveBlockVisual,
|
|
3520
|
+
buildRecorderSlideDeck,
|
|
3521
|
+
BlockThumbnail,
|
|
3522
|
+
RecorderSlidesPanel,
|
|
3005
3523
|
useModalDialog,
|
|
3006
3524
|
RecorderModal,
|
|
3007
3525
|
RecorderPanel
|