@bendyline/squisq-editor-react 2.13.15 → 2.13.16
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-CLULTEKS.js → chunk-54MN2HG7.js} +384 -361
- package/dist/{chunk-FOKUOC7E.js → chunk-ECS2FFXA.js} +252 -177
- package/dist/{chunk-F4D3VBAS.js → chunk-RHH2PVCL.js} +1 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +3 -3
- package/dist/{narrationTimingsFromAudio-ICMDSWPI.js → narrationTimingsFromAudio-O67QKISS.js} +5 -1
- package/dist/recorder/index.js +2 -2
- package/dist/shell/index.js +2 -2
- package/package.json +6 -6
|
@@ -1806,22 +1806,28 @@ function resolveBlockVisual(doc, block, theme, viewport, position = {
|
|
|
1806
1806
|
function buildRecorderSlideDeck(doc, theme, viewport) {
|
|
1807
1807
|
const flat = flattenRenderableBlocks(doc.blocks);
|
|
1808
1808
|
if (flat.length === 0) return [];
|
|
1809
|
-
let
|
|
1809
|
+
let preview;
|
|
1810
1810
|
try {
|
|
1811
|
-
|
|
1812
|
-
|
|
1811
|
+
preview = buildPreviewDoc2(
|
|
1812
|
+
{
|
|
1813
|
+
...doc,
|
|
1814
|
+
documentMedia: doc.documentMedia?.filter((clip) => clip.anchor !== "document")
|
|
1815
|
+
},
|
|
1816
|
+
{ interleaveImages: false }
|
|
1817
|
+
);
|
|
1813
1818
|
} catch {
|
|
1814
|
-
|
|
1819
|
+
preview = null;
|
|
1815
1820
|
}
|
|
1821
|
+
if (preview?.presentationApplied) {
|
|
1822
|
+
return presentationDeck(doc, flat, preview.blocks, theme, viewport);
|
|
1823
|
+
}
|
|
1824
|
+
const slidesById = new Map(
|
|
1825
|
+
(preview?.blocks ?? []).map((slide) => [slide.id, slide])
|
|
1826
|
+
);
|
|
1816
1827
|
return flat.map((block, index) => {
|
|
1817
|
-
const heading = block
|
|
1818
|
-
let bodyText = "";
|
|
1819
|
-
try {
|
|
1820
|
-
bodyText = getBlockBodyText(block);
|
|
1821
|
-
} catch {
|
|
1822
|
-
bodyText = "";
|
|
1823
|
-
}
|
|
1828
|
+
const { heading, bodyText } = blockNotes(block, index);
|
|
1824
1829
|
return {
|
|
1830
|
+
id: block.id,
|
|
1825
1831
|
blockId: block.id,
|
|
1826
1832
|
heading,
|
|
1827
1833
|
bodyText,
|
|
@@ -1837,6 +1843,35 @@ function buildRecorderSlideDeck(doc, theme, viewport) {
|
|
|
1837
1843
|
};
|
|
1838
1844
|
});
|
|
1839
1845
|
}
|
|
1846
|
+
function presentationDeck(doc, flat, slides, theme, viewport) {
|
|
1847
|
+
const blockIndex = new Map(flat.map((block, index) => [block.id, index]));
|
|
1848
|
+
let previous = 0;
|
|
1849
|
+
return slides.map((slide, index) => {
|
|
1850
|
+
const found = slide.sourceBlockId ? blockIndex.get(slide.sourceBlockId) : void 0;
|
|
1851
|
+
const sourceIndex = found ?? previous;
|
|
1852
|
+
previous = sourceIndex;
|
|
1853
|
+
const block = flat[sourceIndex];
|
|
1854
|
+
const { heading, bodyText } = blockNotes(block, sourceIndex);
|
|
1855
|
+
return {
|
|
1856
|
+
id: slide.id,
|
|
1857
|
+
blockId: block.id,
|
|
1858
|
+
...slide.sourceCharOffset !== void 0 ? { sourceCharOffset: slide.sourceCharOffset } : {},
|
|
1859
|
+
heading,
|
|
1860
|
+
bodyText,
|
|
1861
|
+
visual: resolveSlideVisual(doc, block, slide, theme, viewport, index, slides.length)
|
|
1862
|
+
};
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
function blockNotes(block, index) {
|
|
1866
|
+
const heading = block.title?.trim() || `Slide ${index + 1}`;
|
|
1867
|
+
let bodyText = "";
|
|
1868
|
+
try {
|
|
1869
|
+
bodyText = getBlockBodyText(block);
|
|
1870
|
+
} catch {
|
|
1871
|
+
bodyText = "";
|
|
1872
|
+
}
|
|
1873
|
+
return { heading, bodyText };
|
|
1874
|
+
}
|
|
1840
1875
|
function resolveSlideVisual(doc, block, slide, theme, viewport, index, totalBlocks) {
|
|
1841
1876
|
if (slide) {
|
|
1842
1877
|
try {
|
|
@@ -1855,36 +1890,15 @@ function resolveSlideVisual(doc, block, slide, theme, viewport, index, totalBloc
|
|
|
1855
1890
|
}
|
|
1856
1891
|
|
|
1857
1892
|
// src/recorder/slides/RecorderSlidesPanel.tsx
|
|
1858
|
-
import { useBuildNavigation } from "@bendyline/squisq-react";
|
|
1893
|
+
import { BlockRenderer, MediaContext, useBuildNavigation } from "@bendyline/squisq-react";
|
|
1859
1894
|
import { blockBuildSteps, buildSourceText } from "@bendyline/squisq/doc";
|
|
1860
|
-
import {
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1867
|
-
var BlockThumbnail = memo(function BlockThumbnail2({
|
|
1868
|
-
visual,
|
|
1869
|
-
buildPlayback = "all",
|
|
1870
|
-
viewport = VIEWPORT_PRESETS.landscape,
|
|
1871
|
-
basePath = "/",
|
|
1872
|
-
mediaProvider = null
|
|
1873
|
-
}) {
|
|
1874
|
-
return /* @__PURE__ */ jsx3(MediaContext.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx3(
|
|
1875
|
-
BlockRenderer,
|
|
1876
|
-
{
|
|
1877
|
-
buildPlayback,
|
|
1878
|
-
block: visual,
|
|
1879
|
-
blockTime: 0,
|
|
1880
|
-
basePath,
|
|
1881
|
-
viewport
|
|
1882
|
-
}
|
|
1883
|
-
) });
|
|
1884
|
-
});
|
|
1885
|
-
|
|
1886
|
-
// src/recorder/slides/RecorderSlidesPanel.tsx
|
|
1887
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1895
|
+
import {
|
|
1896
|
+
useCallback as useCallback3,
|
|
1897
|
+
useEffect as useEffect4,
|
|
1898
|
+
useRef as useRef2,
|
|
1899
|
+
useState as useState3
|
|
1900
|
+
} from "react";
|
|
1901
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1888
1902
|
var rootStyle = {
|
|
1889
1903
|
flex: "1 1 auto",
|
|
1890
1904
|
minHeight: 0,
|
|
@@ -2000,7 +2014,7 @@ function RecorderSlidesPanel({
|
|
|
2000
2014
|
[step]
|
|
2001
2015
|
);
|
|
2002
2016
|
if (count === 0 || !active) {
|
|
2003
|
-
return /* @__PURE__ */
|
|
2017
|
+
return /* @__PURE__ */ jsx3("div", { style: { ...rootStyle, alignItems: "center", justifyContent: "center", padding: 24 }, children: /* @__PURE__ */ jsx3("p", { style: hintStyle, children: "This document has no slides yet." }) });
|
|
2004
2018
|
}
|
|
2005
2019
|
return /* @__PURE__ */ jsxs3(
|
|
2006
2020
|
"div",
|
|
@@ -2019,7 +2033,7 @@ function RecorderSlidesPanel({
|
|
|
2019
2033
|
count,
|
|
2020
2034
|
builds.count > 0 ? ` \xB7 Build ${builds.cursor.revealed} of ${builds.count}` : ""
|
|
2021
2035
|
] }),
|
|
2022
|
-
/* @__PURE__ */
|
|
2036
|
+
/* @__PURE__ */ jsx3("span", { style: dotsStyle, "aria-hidden": "true", children: slides.map((slide, i) => /* @__PURE__ */ jsx3(
|
|
2023
2037
|
"span",
|
|
2024
2038
|
{
|
|
2025
2039
|
style: {
|
|
@@ -2029,9 +2043,9 @@ function RecorderSlidesPanel({
|
|
|
2029
2043
|
background: i === index ? "var(--squisq-recorder-accent)" : shownBlockIds?.has(slide.blockId) ? "var(--squisq-recorder-text)" : "var(--squisq-recorder-border)"
|
|
2030
2044
|
}
|
|
2031
2045
|
},
|
|
2032
|
-
slide.
|
|
2046
|
+
slide.id
|
|
2033
2047
|
)) }),
|
|
2034
|
-
/* @__PURE__ */
|
|
2048
|
+
/* @__PURE__ */ jsx3(
|
|
2035
2049
|
"button",
|
|
2036
2050
|
{
|
|
2037
2051
|
type: "button",
|
|
@@ -2039,10 +2053,10 @@ function RecorderSlidesPanel({
|
|
|
2039
2053
|
onClick: () => step(-1),
|
|
2040
2054
|
disabled: index <= 0 && builds.cursor.revealed === 0,
|
|
2041
2055
|
"aria-label": "Previous slide",
|
|
2042
|
-
children: /* @__PURE__ */
|
|
2056
|
+
children: /* @__PURE__ */ jsx3(Icon, { icon: "fa-solid fa-chevron-left" })
|
|
2043
2057
|
}
|
|
2044
2058
|
),
|
|
2045
|
-
/* @__PURE__ */
|
|
2059
|
+
/* @__PURE__ */ jsx3(
|
|
2046
2060
|
"button",
|
|
2047
2061
|
{
|
|
2048
2062
|
type: "button",
|
|
@@ -2050,11 +2064,11 @@ function RecorderSlidesPanel({
|
|
|
2050
2064
|
onClick: () => step(1),
|
|
2051
2065
|
disabled: index >= count - 1 && builds.cursor.revealed >= builds.count && builds.cursor.progress >= 1,
|
|
2052
2066
|
"aria-label": "Next slide",
|
|
2053
|
-
children: /* @__PURE__ */
|
|
2067
|
+
children: /* @__PURE__ */ jsx3(Icon, { icon: "fa-solid fa-chevron-right" })
|
|
2054
2068
|
}
|
|
2055
2069
|
)
|
|
2056
2070
|
] }),
|
|
2057
|
-
/* @__PURE__ */
|
|
2071
|
+
/* @__PURE__ */ jsx3("div", { style: stageStyle, children: /* @__PURE__ */ jsx3(
|
|
2058
2072
|
"div",
|
|
2059
2073
|
{
|
|
2060
2074
|
style: {
|
|
@@ -2064,15 +2078,17 @@ function RecorderSlidesPanel({
|
|
|
2064
2078
|
overflow: "hidden",
|
|
2065
2079
|
background: "#000"
|
|
2066
2080
|
},
|
|
2067
|
-
children: active.visual ? /* @__PURE__ */
|
|
2068
|
-
|
|
2081
|
+
children: active.visual ? /* @__PURE__ */ jsx3(
|
|
2082
|
+
RecorderSlideStage,
|
|
2069
2083
|
{
|
|
2070
2084
|
visual: active.visual,
|
|
2071
2085
|
buildPlayback: builds.cursor,
|
|
2072
2086
|
viewport,
|
|
2073
2087
|
basePath,
|
|
2074
|
-
mediaProvider
|
|
2075
|
-
|
|
2088
|
+
mediaProvider,
|
|
2089
|
+
recording
|
|
2090
|
+
},
|
|
2091
|
+
active.id
|
|
2076
2092
|
) : /* @__PURE__ */ jsxs3(
|
|
2077
2093
|
"div",
|
|
2078
2094
|
{
|
|
@@ -2097,14 +2113,58 @@ function RecorderSlidesPanel({
|
|
|
2097
2113
|
}
|
|
2098
2114
|
) }),
|
|
2099
2115
|
/* @__PURE__ */ jsxs3("div", { style: notesStyle, "data-testid": "recorder-slide-notes", children: [
|
|
2100
|
-
/* @__PURE__ */
|
|
2101
|
-
active.bodyText ? /* @__PURE__ */
|
|
2102
|
-
/* @__PURE__ */
|
|
2116
|
+
/* @__PURE__ */ jsx3("p", { style: headingStyle, children: active.heading }),
|
|
2117
|
+
active.bodyText ? /* @__PURE__ */ jsx3("div", { children: active.bodyText }) : /* @__PURE__ */ jsx3("p", { style: hintStyle, children: "No additional narrative for this slide." }),
|
|
2118
|
+
/* @__PURE__ */ jsx3("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." })
|
|
2103
2119
|
] })
|
|
2104
2120
|
]
|
|
2105
2121
|
}
|
|
2106
2122
|
);
|
|
2107
2123
|
}
|
|
2124
|
+
function RecorderSlideStage({
|
|
2125
|
+
visual,
|
|
2126
|
+
buildPlayback,
|
|
2127
|
+
viewport,
|
|
2128
|
+
basePath,
|
|
2129
|
+
mediaProvider,
|
|
2130
|
+
recording
|
|
2131
|
+
}) {
|
|
2132
|
+
const blockTime = useSlideClock(readsBlockClock(visual), recording);
|
|
2133
|
+
return /* @__PURE__ */ jsx3(MediaContext.Provider, { value: mediaProvider, children: /* @__PURE__ */ jsx3(
|
|
2134
|
+
BlockRenderer,
|
|
2135
|
+
{
|
|
2136
|
+
block: visual,
|
|
2137
|
+
buildPlayback,
|
|
2138
|
+
blockTime,
|
|
2139
|
+
isPlaying: true,
|
|
2140
|
+
muted: true,
|
|
2141
|
+
basePath,
|
|
2142
|
+
viewport
|
|
2143
|
+
}
|
|
2144
|
+
) });
|
|
2145
|
+
}
|
|
2146
|
+
function readsBlockClock(visual) {
|
|
2147
|
+
return (visual.layers ?? []).some(
|
|
2148
|
+
(layer) => layer.type === "video" || layer.animation?.type === "countUp"
|
|
2149
|
+
);
|
|
2150
|
+
}
|
|
2151
|
+
function useSlideClock(running, recording) {
|
|
2152
|
+
const [seconds, setSeconds] = useState3(0);
|
|
2153
|
+
const originRef = useRef2(null);
|
|
2154
|
+
useEffect4(() => {
|
|
2155
|
+
if (recording) originRef.current = null;
|
|
2156
|
+
}, [recording]);
|
|
2157
|
+
useEffect4(() => {
|
|
2158
|
+
if (!running) return;
|
|
2159
|
+
let frame = requestAnimationFrame(function tick(now) {
|
|
2160
|
+
const origin = originRef.current ?? (originRef.current = now);
|
|
2161
|
+
setSeconds((now - origin) / 1e3);
|
|
2162
|
+
frame = requestAnimationFrame(tick);
|
|
2163
|
+
});
|
|
2164
|
+
return () => cancelAnimationFrame(frame);
|
|
2165
|
+
}, [running]);
|
|
2166
|
+
return seconds;
|
|
2167
|
+
}
|
|
2108
2168
|
|
|
2109
2169
|
// src/recorder/RecorderModal.tsx
|
|
2110
2170
|
import { recordBuildAdvance } from "@bendyline/squisq/schemas";
|
|
@@ -2114,19 +2174,21 @@ import {
|
|
|
2114
2174
|
useEffect as useEffect5,
|
|
2115
2175
|
useId as useId2,
|
|
2116
2176
|
useMemo,
|
|
2117
|
-
useRef as
|
|
2118
|
-
useState as
|
|
2177
|
+
useRef as useRef3,
|
|
2178
|
+
useState as useState4
|
|
2119
2179
|
} from "react";
|
|
2120
|
-
import { VIEWPORT_PRESETS
|
|
2180
|
+
import { VIEWPORT_PRESETS } from "@bendyline/squisq/schemas";
|
|
2121
2181
|
import {
|
|
2122
2182
|
EMPTY_ADVANCE_LOG,
|
|
2183
|
+
EMPTY_SLIDE_MARK_LOG,
|
|
2123
2184
|
advanceCoverage,
|
|
2124
2185
|
buildAdvanceTimingJson,
|
|
2186
|
+
recordSlideMark,
|
|
2125
2187
|
recordSlideShown
|
|
2126
2188
|
} from "@bendyline/squisq/narration";
|
|
2127
2189
|
|
|
2128
2190
|
// src/recorder/RecorderScreenSettings.tsx
|
|
2129
|
-
import { jsx as
|
|
2191
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
2130
2192
|
var field = { display: "flex", flexDirection: "column", gap: 4, minWidth: 0 };
|
|
2131
2193
|
var input = {
|
|
2132
2194
|
width: "100%",
|
|
@@ -2156,7 +2218,7 @@ function RecorderScreenSettings({
|
|
|
2156
2218
|
fontSize: 13
|
|
2157
2219
|
},
|
|
2158
2220
|
children: [
|
|
2159
|
-
/* @__PURE__ */
|
|
2221
|
+
/* @__PURE__ */ jsx4("legend", { children: "What to record" }),
|
|
2160
2222
|
/* @__PURE__ */ jsxs4(
|
|
2161
2223
|
"div",
|
|
2162
2224
|
{
|
|
@@ -2175,10 +2237,10 @@ function RecorderScreenSettings({
|
|
|
2175
2237
|
value: value.displaySurface ?? "",
|
|
2176
2238
|
onChange: (event) => onChange({ ...value, displaySurface: event.target.value || void 0 }),
|
|
2177
2239
|
children: [
|
|
2178
|
-
/* @__PURE__ */
|
|
2179
|
-
/* @__PURE__ */
|
|
2180
|
-
/* @__PURE__ */
|
|
2181
|
-
/* @__PURE__ */
|
|
2240
|
+
/* @__PURE__ */ jsx4("option", { value: "", children: "Any available surface" }),
|
|
2241
|
+
/* @__PURE__ */ jsx4("option", { value: "monitor", children: "Entire screen" }),
|
|
2242
|
+
/* @__PURE__ */ jsx4("option", { value: "window", children: "Application window" }),
|
|
2243
|
+
/* @__PURE__ */ jsx4("option", { value: "browser", children: "Browser tab (when available)" })
|
|
2182
2244
|
]
|
|
2183
2245
|
}
|
|
2184
2246
|
)
|
|
@@ -2195,13 +2257,13 @@ function RecorderScreenSettings({
|
|
|
2195
2257
|
crop: event.target.value === "region" ? { x: 0, y: 0, width: 1280, height: 720 } : void 0
|
|
2196
2258
|
}),
|
|
2197
2259
|
children: [
|
|
2198
|
-
/* @__PURE__ */
|
|
2199
|
-
/* @__PURE__ */
|
|
2260
|
+
/* @__PURE__ */ jsx4("option", { value: "full", children: "Whole selected surface" }),
|
|
2261
|
+
/* @__PURE__ */ jsx4("option", { value: "region", children: "Region by coordinates" })
|
|
2200
2262
|
]
|
|
2201
2263
|
}
|
|
2202
2264
|
)
|
|
2203
2265
|
] }),
|
|
2204
|
-
crop && /* @__PURE__ */
|
|
2266
|
+
crop && /* @__PURE__ */ jsx4(
|
|
2205
2267
|
"div",
|
|
2206
2268
|
{
|
|
2207
2269
|
style: {
|
|
@@ -2217,7 +2279,7 @@ function RecorderScreenSettings({
|
|
|
2217
2279
|
width: "Region width (px)",
|
|
2218
2280
|
height: "Region height (px)"
|
|
2219
2281
|
}[key],
|
|
2220
|
-
/* @__PURE__ */
|
|
2282
|
+
/* @__PURE__ */ jsx4(
|
|
2221
2283
|
"input",
|
|
2222
2284
|
{
|
|
2223
2285
|
style: input,
|
|
@@ -2239,7 +2301,7 @@ function RecorderScreenSettings({
|
|
|
2239
2301
|
"Choose a screen, window or tab in the picker, then check the preview. Available choices depend on your browser or app.",
|
|
2240
2302
|
value.crop && " Coordinates start at the selected surface\u2019s top-left, in captured pixels. Only this region is saved; audio is unchanged."
|
|
2241
2303
|
] }),
|
|
2242
|
-
/* @__PURE__ */
|
|
2304
|
+
/* @__PURE__ */ jsx4(
|
|
2243
2305
|
"button",
|
|
2244
2306
|
{
|
|
2245
2307
|
type: "button",
|
|
@@ -2279,7 +2341,7 @@ function narrationCaptureSummary(withCamera) {
|
|
|
2279
2341
|
}
|
|
2280
2342
|
|
|
2281
2343
|
// src/recorder/RecorderModal.tsx
|
|
2282
|
-
import { Fragment as Fragment3, jsx as
|
|
2344
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2283
2345
|
var overlayStyle = {
|
|
2284
2346
|
position: "fixed",
|
|
2285
2347
|
inset: 0,
|
|
@@ -2637,26 +2699,26 @@ function RecorderModal({
|
|
|
2637
2699
|
maxRecordingBytes
|
|
2638
2700
|
}) {
|
|
2639
2701
|
const initialToggles = toggleStateFromMode(initialMode);
|
|
2640
|
-
const [micOn, setMicOn] =
|
|
2641
|
-
const [cameraOn, setCameraOn] =
|
|
2642
|
-
const [screenOn, setScreenOn] =
|
|
2643
|
-
const [sourceText, setSourceText] =
|
|
2644
|
-
const [basename, setBasename] =
|
|
2645
|
-
const [includeSystemAudio, setIncludeSystemAudio] =
|
|
2646
|
-
const [isSaving, setIsSaving] =
|
|
2647
|
-
const [saveError, setSaveError] =
|
|
2648
|
-
const [playbackUrl, setPlaybackUrl] =
|
|
2649
|
-
const [cameraPlaybackUrl, setCameraPlaybackUrl] =
|
|
2650
|
-
const [playbackPositionMs, setPlaybackPositionMs] =
|
|
2651
|
-
const [panelMode, setPanelMode] =
|
|
2702
|
+
const [micOn, setMicOn] = useState4(initialToggles.micOn);
|
|
2703
|
+
const [cameraOn, setCameraOn] = useState4(initialToggles.cameraOn);
|
|
2704
|
+
const [screenOn, setScreenOn] = useState4(initialToggles.screenOn);
|
|
2705
|
+
const [sourceText, setSourceText] = useState4("");
|
|
2706
|
+
const [basename, setBasename] = useState4("");
|
|
2707
|
+
const [includeSystemAudio, setIncludeSystemAudio] = useState4(false);
|
|
2708
|
+
const [isSaving, setIsSaving] = useState4(false);
|
|
2709
|
+
const [saveError, setSaveError] = useState4(null);
|
|
2710
|
+
const [playbackUrl, setPlaybackUrl] = useState4(null);
|
|
2711
|
+
const [cameraPlaybackUrl, setCameraPlaybackUrl] = useState4(null);
|
|
2712
|
+
const [playbackPositionMs, setPlaybackPositionMs] = useState4(0);
|
|
2713
|
+
const [panelMode, setPanelMode] = useState4("none");
|
|
2652
2714
|
const narrationOn = panelMode === "narration" || panelMode === "both";
|
|
2653
2715
|
const slidesOn = panelMode === "slides" || panelMode === "both";
|
|
2654
2716
|
const narrationRecording = narrationOn && Boolean(narration?.recording);
|
|
2655
2717
|
const expanded = isExpandedPanel(panelMode);
|
|
2656
|
-
const [narrationRequesting, setNarrationRequesting] =
|
|
2657
|
-
const [countingIn, setCountingIn] =
|
|
2658
|
-
const [narrationPreview, setNarrationPreview] =
|
|
2659
|
-
const [deviceSettings, setDeviceSettings] =
|
|
2718
|
+
const [narrationRequesting, setNarrationRequesting] = useState4(false);
|
|
2719
|
+
const [countingIn, setCountingIn] = useState4(false);
|
|
2720
|
+
const [narrationPreview, setNarrationPreview] = useState4(null);
|
|
2721
|
+
const [deviceSettings, setDeviceSettings] = useState4(() => ({
|
|
2660
2722
|
...DEFAULT_RECORDER_DEVICE_SETTINGS,
|
|
2661
2723
|
audio: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.audio },
|
|
2662
2724
|
camera: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.camera },
|
|
@@ -2664,11 +2726,11 @@ function RecorderModal({
|
|
|
2664
2726
|
screenAudio: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.screenAudio },
|
|
2665
2727
|
encoding: { ...DEFAULT_RECORDER_DEVICE_SETTINGS.encoding }
|
|
2666
2728
|
}));
|
|
2667
|
-
const overlayRef =
|
|
2668
|
-
const dialogRef =
|
|
2729
|
+
const overlayRef = useRef3(null);
|
|
2730
|
+
const dialogRef = useRef3(null);
|
|
2669
2731
|
const headingId = useId2();
|
|
2670
|
-
const previewRef =
|
|
2671
|
-
const cameraPreviewRef =
|
|
2732
|
+
const previewRef = useRef3(null);
|
|
2733
|
+
const cameraPreviewRef = useRef3(null);
|
|
2672
2734
|
const derivedSource = deriveSource({ micOn, cameraOn, screenOn });
|
|
2673
2735
|
const canCapture = derivedSource !== null;
|
|
2674
2736
|
const source = derivedSource ?? "mic";
|
|
@@ -2714,7 +2776,7 @@ function RecorderModal({
|
|
|
2714
2776
|
});
|
|
2715
2777
|
const filenameSeed = recordingFilenameSeed(source, recorder.stream, micOn || includeSystemAudio);
|
|
2716
2778
|
const narrationAvailable = Boolean(narration?.doc);
|
|
2717
|
-
const basenameRef =
|
|
2779
|
+
const basenameRef = useRef3(basename);
|
|
2718
2780
|
basenameRef.current = basename;
|
|
2719
2781
|
const stage = useNarrationStage({
|
|
2720
2782
|
doc: narration?.doc ?? null,
|
|
@@ -2740,18 +2802,18 @@ function RecorderModal({
|
|
|
2740
2802
|
videoKeyFrameIntervalCount: encoding.videoKeyFrameIntervalCount
|
|
2741
2803
|
}
|
|
2742
2804
|
});
|
|
2743
|
-
const stageRef =
|
|
2805
|
+
const stageRef = useRef3(stage);
|
|
2744
2806
|
stageRef.current = stage;
|
|
2745
|
-
const slidesViewport = slides?.viewport ??
|
|
2807
|
+
const slidesViewport = slides?.viewport ?? VIEWPORT_PRESETS.landscape;
|
|
2746
2808
|
const slideDeck = useMemo(
|
|
2747
2809
|
() => slides?.doc ? buildRecorderSlideDeck(slides.doc, slides.theme, slidesViewport) : [],
|
|
2748
2810
|
[slides?.doc, slides?.theme, slidesViewport]
|
|
2749
2811
|
);
|
|
2750
2812
|
const slidesAvailable = slideDeck.length > 0;
|
|
2751
2813
|
const slidesCaptureTimings = Boolean(slides?.captureTimings && slides?.doc);
|
|
2752
|
-
const [slideIndex, setSlideIndex] =
|
|
2753
|
-
const [buildLog, setBuildLog] =
|
|
2754
|
-
const buildLogRef =
|
|
2814
|
+
const [slideIndex, setSlideIndex] = useState4(0);
|
|
2815
|
+
const [buildLog, setBuildLog] = useState4([]);
|
|
2816
|
+
const buildLogRef = useRef3(buildLog);
|
|
2755
2817
|
buildLogRef.current = buildLog;
|
|
2756
2818
|
const handleBuildShown = useCallback4(
|
|
2757
2819
|
(blockId, step, sourceText2) => {
|
|
@@ -2763,13 +2825,16 @@ function RecorderModal({
|
|
|
2763
2825
|
},
|
|
2764
2826
|
[recorder]
|
|
2765
2827
|
);
|
|
2766
|
-
const [advanceLog, setAdvanceLog] =
|
|
2767
|
-
const [
|
|
2768
|
-
const
|
|
2828
|
+
const [advanceLog, setAdvanceLog] = useState4(EMPTY_ADVANCE_LOG);
|
|
2829
|
+
const [slideMarks, setSlideMarks] = useState4(EMPTY_SLIDE_MARK_LOG);
|
|
2830
|
+
const slideMarksRef = useRef3(slideMarks);
|
|
2831
|
+
slideMarksRef.current = slideMarks;
|
|
2832
|
+
const [applySlideTimings, setApplySlideTimings] = useState4(true);
|
|
2833
|
+
const slideIndexRef = useRef3(slideIndex);
|
|
2769
2834
|
slideIndexRef.current = slideIndex;
|
|
2770
|
-
const advanceLogRef =
|
|
2835
|
+
const advanceLogRef = useRef3(advanceLog);
|
|
2771
2836
|
advanceLogRef.current = advanceLog;
|
|
2772
|
-
const slideDeckRef =
|
|
2837
|
+
const slideDeckRef = useRef3(slideDeck);
|
|
2773
2838
|
slideDeckRef.current = slideDeck;
|
|
2774
2839
|
const shownBlockIds = useMemo(
|
|
2775
2840
|
() => new Set(advanceLog.map((advance) => advance.blockId)),
|
|
@@ -2780,15 +2845,18 @@ function RecorderModal({
|
|
|
2780
2845
|
const clamped = clampSlideIndex(next, slideDeckRef.current.length);
|
|
2781
2846
|
setSlideIndex(clamped);
|
|
2782
2847
|
const elapsedMs = recorder.getElapsedMs();
|
|
2783
|
-
const
|
|
2784
|
-
if (elapsedMs === null || !blockId) return;
|
|
2785
|
-
setAdvanceLog((log) => recordSlideShown(log, blockId, elapsedMs));
|
|
2848
|
+
const slide = slideDeckRef.current[clamped];
|
|
2849
|
+
if (elapsedMs === null || !slide?.blockId) return;
|
|
2850
|
+
setAdvanceLog((log) => recordSlideShown(log, slide.blockId, elapsedMs));
|
|
2851
|
+
const offset = slide.sourceCharOffset;
|
|
2852
|
+
if (offset !== void 0) setSlideMarks((log) => recordSlideMark(log, offset, elapsedMs));
|
|
2786
2853
|
},
|
|
2787
2854
|
[recorder]
|
|
2788
2855
|
);
|
|
2789
|
-
const slideDeckKey = slideDeck.map((slide) => slide.blockId).join("\0");
|
|
2856
|
+
const slideDeckKey = [...new Set(slideDeck.map((slide) => slide.blockId))].join("\0");
|
|
2790
2857
|
useEffect5(() => {
|
|
2791
2858
|
setAdvanceLog(EMPTY_ADVANCE_LOG);
|
|
2859
|
+
setSlideMarks(EMPTY_SLIDE_MARK_LOG);
|
|
2792
2860
|
setBuildLog([]);
|
|
2793
2861
|
setSlideIndex(0);
|
|
2794
2862
|
}, [slidesOn, slideDeckKey]);
|
|
@@ -2819,7 +2887,7 @@ function RecorderModal({
|
|
|
2819
2887
|
}
|
|
2820
2888
|
);
|
|
2821
2889
|
}, [narrationMicDeviceId, narrationRecording]);
|
|
2822
|
-
const prevNarrationOnRef =
|
|
2890
|
+
const prevNarrationOnRef = useRef3(narrationOn);
|
|
2823
2891
|
useEffect5(() => {
|
|
2824
2892
|
const was = prevNarrationOnRef.current;
|
|
2825
2893
|
prevNarrationOnRef.current = narrationOn;
|
|
@@ -2847,7 +2915,7 @@ function RecorderModal({
|
|
|
2847
2915
|
}, [narrationOn]);
|
|
2848
2916
|
const narrationMicLive = stage.controller.mic.status === "live";
|
|
2849
2917
|
const narrationPreviewWanted = narrationRecording && stage.recorder.withCamera && narrationMicLive && stage.recorder.cameraStream === null && stage.recorder.state !== "processing" && stage.recorder.state !== "review" && stage.recorder.state !== "saving";
|
|
2850
|
-
const narrationPreviewRef =
|
|
2918
|
+
const narrationPreviewRef = useRef3(null);
|
|
2851
2919
|
useEffect5(() => {
|
|
2852
2920
|
const existing = narrationPreviewRef.current;
|
|
2853
2921
|
if (existing) {
|
|
@@ -2935,13 +3003,14 @@ function RecorderModal({
|
|
|
2935
3003
|
};
|
|
2936
3004
|
}, [cameraBlob]);
|
|
2937
3005
|
const captureKey = `${source}:${cameraOn ? micOn : ""}:${includeSystemAudio}:${JSON.stringify(deviceSettings)}`;
|
|
2938
|
-
const previousKeyRef =
|
|
2939
|
-
const dualSaveProgressRef =
|
|
3006
|
+
const previousKeyRef = useRef3(captureKey);
|
|
3007
|
+
const dualSaveProgressRef = useRef3({});
|
|
2940
3008
|
useEffect5(() => {
|
|
2941
3009
|
if (previousKeyRef.current !== captureKey) {
|
|
2942
3010
|
previousKeyRef.current = captureKey;
|
|
2943
3011
|
dualSaveProgressRef.current = {};
|
|
2944
3012
|
setAdvanceLog(EMPTY_ADVANCE_LOG);
|
|
3013
|
+
setSlideMarks(EMPTY_SLIDE_MARK_LOG);
|
|
2945
3014
|
recorder.cancel();
|
|
2946
3015
|
}
|
|
2947
3016
|
}, [captureKey, recorder]);
|
|
@@ -2995,8 +3064,13 @@ function RecorderModal({
|
|
|
2995
3064
|
}
|
|
2996
3065
|
setBuildLog([]);
|
|
2997
3066
|
recorder.start();
|
|
2998
|
-
const
|
|
2999
|
-
setAdvanceLog(
|
|
3067
|
+
const slide = slideDeckRef.current[slideIndexRef.current];
|
|
3068
|
+
setAdvanceLog(
|
|
3069
|
+
slide?.blockId ? recordSlideShown(EMPTY_ADVANCE_LOG, slide.blockId, 0) : EMPTY_ADVANCE_LOG
|
|
3070
|
+
);
|
|
3071
|
+
setSlideMarks(
|
|
3072
|
+
slide?.sourceCharOffset !== void 0 ? recordSlideMark(EMPTY_SLIDE_MARK_LOG, slide.sourceCharOffset, 0) : EMPTY_SLIDE_MARK_LOG
|
|
3073
|
+
);
|
|
3000
3074
|
}, [narrationOn, recorder]);
|
|
3001
3075
|
const handleStop = useCallback4(async () => {
|
|
3002
3076
|
setSaveError(null);
|
|
@@ -3013,7 +3087,7 @@ function RecorderModal({
|
|
|
3013
3087
|
const log = advanceLogRef.current;
|
|
3014
3088
|
if (log.length === 0) return null;
|
|
3015
3089
|
const timing = {
|
|
3016
|
-
...buildAdvanceTimingJson(doc, log, durationSec),
|
|
3090
|
+
...buildAdvanceTimingJson(doc, log, durationSec, { slides: slideMarksRef.current }),
|
|
3017
3091
|
builds: buildLogRef.current
|
|
3018
3092
|
};
|
|
3019
3093
|
const encoded = encodeNarrationTimingJson(timing);
|
|
@@ -3189,6 +3263,7 @@ function RecorderModal({
|
|
|
3189
3263
|
const handleDiscard = useCallback4(() => {
|
|
3190
3264
|
dualSaveProgressRef.current = {};
|
|
3191
3265
|
setAdvanceLog(EMPTY_ADVANCE_LOG);
|
|
3266
|
+
setSlideMarks(EMPTY_SLIDE_MARK_LOG);
|
|
3192
3267
|
recorder.reset();
|
|
3193
3268
|
if (narrationOn) stageRef.current.controller.restart();
|
|
3194
3269
|
}, [narrationOn, recorder]);
|
|
@@ -3216,7 +3291,7 @@ function RecorderModal({
|
|
|
3216
3291
|
() => slides?.doc && showTimingCheckbox ? advanceCoverage(slides.doc, advanceLog) : null,
|
|
3217
3292
|
[slides?.doc, showTimingCheckbox, advanceLog]
|
|
3218
3293
|
);
|
|
3219
|
-
const [timingDownloadUrl, setTimingDownloadUrl] =
|
|
3294
|
+
const [timingDownloadUrl, setTimingDownloadUrl] = useState4(null);
|
|
3220
3295
|
const downloadFilename = useMemo(
|
|
3221
3296
|
() => !recorder.blob ? "" : buildFilename(
|
|
3222
3297
|
source === "mic" ? "audio" : "video",
|
|
@@ -3234,7 +3309,7 @@ function RecorderModal({
|
|
|
3234
3309
|
}
|
|
3235
3310
|
const duration = recorder.durationMs / 1e3;
|
|
3236
3311
|
const encoded = slidesOn && slidesCaptureTimings && applySlideTimings && slides?.doc && advanceLog.length > 0 ? encodeNarrationTimingJson({
|
|
3237
|
-
...buildAdvanceTimingJson(slides.doc, advanceLog, duration),
|
|
3312
|
+
...buildAdvanceTimingJson(slides.doc, advanceLog, duration, { slides: slideMarks }),
|
|
3238
3313
|
builds: buildLog
|
|
3239
3314
|
}) : source === "mic" ? encodeTimingJson(buildTimingJson(sourceText, duration)) : null;
|
|
3240
3315
|
if (encoded === null) {
|
|
@@ -3256,6 +3331,7 @@ function RecorderModal({
|
|
|
3256
3331
|
applySlideTimings,
|
|
3257
3332
|
slides?.doc,
|
|
3258
3333
|
advanceLog,
|
|
3334
|
+
slideMarks,
|
|
3259
3335
|
source,
|
|
3260
3336
|
sourceText
|
|
3261
3337
|
]);
|
|
@@ -3329,7 +3405,7 @@ function RecorderModal({
|
|
|
3329
3405
|
};
|
|
3330
3406
|
}
|
|
3331
3407
|
};
|
|
3332
|
-
return /* @__PURE__ */
|
|
3408
|
+
return /* @__PURE__ */ jsx5(
|
|
3333
3409
|
"div",
|
|
3334
3410
|
{
|
|
3335
3411
|
ref: overlayRef,
|
|
@@ -3355,7 +3431,7 @@ function RecorderModal({
|
|
|
3355
3431
|
"aria-labelledby": headingId,
|
|
3356
3432
|
tabIndex: -1,
|
|
3357
3433
|
children: [
|
|
3358
|
-
/* @__PURE__ */
|
|
3434
|
+
/* @__PURE__ */ jsx5("h2", { id: headingId, style: titleStyle, children: title }),
|
|
3359
3435
|
/* @__PURE__ */ jsxs5("div", { style: expanded ? bodyRowStyle : void 0, children: [
|
|
3360
3436
|
/* @__PURE__ */ jsxs5(
|
|
3361
3437
|
"div",
|
|
@@ -3365,12 +3441,12 @@ function RecorderModal({
|
|
|
3365
3441
|
...panelMode === "both" ? { flex: "0 0 min(280px, 24vw)" } : {}
|
|
3366
3442
|
} : void 0,
|
|
3367
3443
|
children: [
|
|
3368
|
-
/* @__PURE__ */
|
|
3369
|
-
groupIndex > 0 && /* @__PURE__ */
|
|
3370
|
-
/* @__PURE__ */
|
|
3444
|
+
/* @__PURE__ */ jsx5("div", { style: toggleRowStyle, role: "group", "aria-label": "Capture sources", children: TOGGLE_GROUPS.map((group, groupIndex) => /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
3445
|
+
groupIndex > 0 && /* @__PURE__ */ jsx5("div", { "aria-hidden": "true", style: groupDividerStyle }),
|
|
3446
|
+
/* @__PURE__ */ jsx5("div", { style: toggleGroupStyle, children: group.toggles.map((t) => {
|
|
3371
3447
|
if (t.key === "systemAudio" && !canIncludeSystemAudio) return null;
|
|
3372
3448
|
const props = narrationRecording ? narrationToggleFor(t.key) : simpleToggleProps(t.key);
|
|
3373
|
-
return /* @__PURE__ */
|
|
3449
|
+
return /* @__PURE__ */ jsx5(
|
|
3374
3450
|
"button",
|
|
3375
3451
|
{
|
|
3376
3452
|
type: "button",
|
|
@@ -3385,10 +3461,10 @@ function RecorderModal({
|
|
|
3385
3461
|
);
|
|
3386
3462
|
}) })
|
|
3387
3463
|
] }, group.label)) }),
|
|
3388
|
-
/* @__PURE__ */
|
|
3464
|
+
/* @__PURE__ */ jsx5("p", { style: summaryStyle, children: narrationRecording ? narrationCaptureSummary(stage.recorder.withCamera) : captureSummary(micOn, cameraOn, screenOn, includeSystemAudio) }),
|
|
3389
3465
|
/* @__PURE__ */ jsxs5("div", { style: modeTogglesStyle, children: [
|
|
3390
3466
|
narrationAvailable && /* @__PURE__ */ jsxs5("label", { style: checkboxRowStyle, children: [
|
|
3391
|
-
/* @__PURE__ */
|
|
3467
|
+
/* @__PURE__ */ jsx5(
|
|
3392
3468
|
"input",
|
|
3393
3469
|
{
|
|
3394
3470
|
type: "checkbox",
|
|
@@ -3402,7 +3478,7 @@ function RecorderModal({
|
|
|
3402
3478
|
"Show narration mode"
|
|
3403
3479
|
] }),
|
|
3404
3480
|
slidesAvailable && /* @__PURE__ */ jsxs5("label", { style: checkboxRowStyle, children: [
|
|
3405
|
-
/* @__PURE__ */
|
|
3481
|
+
/* @__PURE__ */ jsx5(
|
|
3406
3482
|
"input",
|
|
3407
3483
|
{
|
|
3408
3484
|
type: "checkbox",
|
|
@@ -3416,7 +3492,7 @@ function RecorderModal({
|
|
|
3416
3492
|
"Show slides mode"
|
|
3417
3493
|
] })
|
|
3418
3494
|
] }),
|
|
3419
|
-
/* @__PURE__ */
|
|
3495
|
+
/* @__PURE__ */ jsx5(
|
|
3420
3496
|
RecorderDeviceQuickPicks,
|
|
3421
3497
|
{
|
|
3422
3498
|
devices: mediaDevices,
|
|
@@ -3435,7 +3511,7 @@ function RecorderModal({
|
|
|
3435
3511
|
disabled: deviceSettingsLocked
|
|
3436
3512
|
}
|
|
3437
3513
|
),
|
|
3438
|
-
!narrationRecording && screenOn && /* @__PURE__ */
|
|
3514
|
+
!narrationRecording && screenOn && /* @__PURE__ */ jsx5(
|
|
3439
3515
|
RecorderScreenSettings,
|
|
3440
3516
|
{
|
|
3441
3517
|
value: deviceSettings.screen,
|
|
@@ -3448,7 +3524,7 @@ function RecorderModal({
|
|
|
3448
3524
|
}
|
|
3449
3525
|
}
|
|
3450
3526
|
),
|
|
3451
|
-
/* @__PURE__ */
|
|
3527
|
+
/* @__PURE__ */ jsx5(
|
|
3452
3528
|
RecorderDeviceSettingsPanel,
|
|
3453
3529
|
{
|
|
3454
3530
|
value: deviceSettings,
|
|
@@ -3463,10 +3539,10 @@ function RecorderModal({
|
|
|
3463
3539
|
cameraStream: activeCameraStream
|
|
3464
3540
|
}
|
|
3465
3541
|
),
|
|
3466
|
-
!narrationRecording && recorder.error && /* @__PURE__ */
|
|
3542
|
+
!narrationRecording && recorder.error && /* @__PURE__ */ jsx5("div", { style: errorStyle, children: recorder.error.message }),
|
|
3467
3543
|
!narrationRecording && saveError && /* @__PURE__ */ jsxs5("div", { role: "alert", style: errorStyle, children: [
|
|
3468
3544
|
saveError,
|
|
3469
|
-
/* @__PURE__ */
|
|
3545
|
+
/* @__PURE__ */ jsx5("p", { style: { marginBottom: 0 }, children: "Your recording is still available below. Download a copy before closing, or try saving again." })
|
|
3470
3546
|
] }),
|
|
3471
3547
|
/* @__PURE__ */ jsxs5("p", { style: summaryStyle, children: [
|
|
3472
3548
|
"Recording size:",
|
|
@@ -3482,9 +3558,9 @@ function RecorderModal({
|
|
|
3482
3558
|
" ",
|
|
3483
3559
|
"total. Final encoding may add more data."
|
|
3484
3560
|
] }),
|
|
3485
|
-
!narrationRecording && recorder.limitReached && /* @__PURE__ */
|
|
3486
|
-
narrationOn && (stage.recorder.error ?? stage.controller.mic.error) && /* @__PURE__ */
|
|
3487
|
-
narrationRecording && narrationCameraStream && /* @__PURE__ */
|
|
3561
|
+
!narrationRecording && 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." }),
|
|
3562
|
+
narrationOn && (stage.recorder.error ?? stage.controller.mic.error) && /* @__PURE__ */ jsx5("div", { style: errorStyle, children: (stage.recorder.error ?? stage.controller.mic.error)?.message }),
|
|
3563
|
+
narrationRecording && narrationCameraStream && /* @__PURE__ */ jsx5("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx5(
|
|
3488
3564
|
"video",
|
|
3489
3565
|
{
|
|
3490
3566
|
ref: previewRef,
|
|
@@ -3494,10 +3570,10 @@ function RecorderModal({
|
|
|
3494
3570
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
3495
3571
|
}
|
|
3496
3572
|
) }),
|
|
3497
|
-
narrationRecording && !narrationCameraStream && narrationTakeDone && /* @__PURE__ */
|
|
3498
|
-
narrationRecording && !narrationCameraStream && !narrationTakeDone && stage.recorder.withCamera && /* @__PURE__ */
|
|
3573
|
+
narrationRecording && !narrationCameraStream && narrationTakeDone && /* @__PURE__ */ jsx5("div", { style: audioMeterStyle, children: stage.recorder.take ? `\u2713 Recorded ${formatDurationMs(stage.recorder.take.durationSec * 1e3)}` : "\u25CF Processing take\u2026" }),
|
|
3574
|
+
narrationRecording && !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." }) }),
|
|
3499
3575
|
narrationRecording && !narrationCameraStream && !narrationTakeDone && !stage.recorder.withCamera && /* @__PURE__ */ jsxs5("div", { style: { ...audioMeterStyle, position: "relative", overflow: "hidden" }, children: [
|
|
3500
|
-
/* @__PURE__ */
|
|
3576
|
+
/* @__PURE__ */ jsx5(
|
|
3501
3577
|
"div",
|
|
3502
3578
|
{
|
|
3503
3579
|
"aria-hidden": "true",
|
|
@@ -3507,11 +3583,11 @@ function RecorderModal({
|
|
|
3507
3583
|
}
|
|
3508
3584
|
}
|
|
3509
3585
|
),
|
|
3510
|
-
/* @__PURE__ */
|
|
3586
|
+
/* @__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." })
|
|
3511
3587
|
] }),
|
|
3512
|
-
!narrationRecording && !showPreview && /* @__PURE__ */
|
|
3588
|
+
!narrationRecording && !showPreview && /* @__PURE__ */ jsx5("div", { style: previewBoxStyle, children: /* @__PURE__ */ jsx5("span", { children: screenOn ? "Choose a screen or window to preview what will be recorded." : "Click Start preview to prepare a recording." }) }),
|
|
3513
3589
|
!narrationRecording && showPreview && recorder.state !== "stopped" && !isAudioOnly && /* @__PURE__ */ jsxs5("div", { style: isDual ? { ...previewBoxStyle, position: "relative" } : previewBoxStyle, children: [
|
|
3514
|
-
/* @__PURE__ */
|
|
3590
|
+
/* @__PURE__ */ jsx5(
|
|
3515
3591
|
"video",
|
|
3516
3592
|
{
|
|
3517
3593
|
ref: previewRef,
|
|
@@ -3521,7 +3597,7 @@ function RecorderModal({
|
|
|
3521
3597
|
style: { width: "100%", height: "100%", objectFit: "contain" }
|
|
3522
3598
|
}
|
|
3523
3599
|
),
|
|
3524
|
-
isDual && /* @__PURE__ */
|
|
3600
|
+
isDual && /* @__PURE__ */ jsx5(
|
|
3525
3601
|
"video",
|
|
3526
3602
|
{
|
|
3527
3603
|
ref: cameraPreviewRef,
|
|
@@ -3542,12 +3618,12 @@ function RecorderModal({
|
|
|
3542
3618
|
}
|
|
3543
3619
|
)
|
|
3544
3620
|
] }),
|
|
3545
|
-
!narrationRecording && showPreview && recorder.state !== "stopped" && isAudioOnly && /* @__PURE__ */
|
|
3621
|
+
!narrationRecording && showPreview && recorder.state !== "stopped" && isAudioOnly && /* @__PURE__ */ jsx5("div", { style: audioMeterStyle, children: recorder.state === "recording" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3546
3622
|
"\u25CF Recording ",
|
|
3547
3623
|
formatDurationMs(recorder.durationMs)
|
|
3548
|
-
] }) : /* @__PURE__ */
|
|
3624
|
+
] }) : /* @__PURE__ */ jsx5(Fragment3, { children: "Microphone ready" }) }),
|
|
3549
3625
|
!narrationRecording && recorder.state === "stopped" && playbackUrl && !isAudioOnly && /* @__PURE__ */ jsxs5("div", { style: { ...previewBoxStyle, position: "relative" }, children: [
|
|
3550
|
-
/* @__PURE__ */
|
|
3626
|
+
/* @__PURE__ */ jsx5(
|
|
3551
3627
|
"video",
|
|
3552
3628
|
{
|
|
3553
3629
|
src: playbackUrl,
|
|
@@ -3574,8 +3650,8 @@ function RecorderModal({
|
|
|
3574
3650
|
)
|
|
3575
3651
|
] }),
|
|
3576
3652
|
!narrationRecording && recorder.state === "stopped" && isDual && cameraPlaybackUrl && /* @__PURE__ */ jsxs5("div", { style: { marginBottom: 12 }, children: [
|
|
3577
|
-
/* @__PURE__ */
|
|
3578
|
-
/* @__PURE__ */
|
|
3653
|
+
/* @__PURE__ */ jsx5("div", { style: summaryStyle, children: "Camera (picture-in-picture)" }),
|
|
3654
|
+
/* @__PURE__ */ jsx5(
|
|
3579
3655
|
"video",
|
|
3580
3656
|
{
|
|
3581
3657
|
src: cameraPlaybackUrl,
|
|
@@ -3596,7 +3672,7 @@ function RecorderModal({
|
|
|
3596
3672
|
"\u2713 Recorded ",
|
|
3597
3673
|
formatDurationMs(recorder.durationMs)
|
|
3598
3674
|
] }),
|
|
3599
|
-
/* @__PURE__ */
|
|
3675
|
+
/* @__PURE__ */ jsx5("audio", { src: playbackUrl, controls: true, style: { width: "100%" } })
|
|
3600
3676
|
] }),
|
|
3601
3677
|
!narrationRecording && canSave && playbackUrl && /* @__PURE__ */ jsxs5(
|
|
3602
3678
|
"div",
|
|
@@ -3608,8 +3684,8 @@ function RecorderModal({
|
|
|
3608
3684
|
marginBottom: 12
|
|
3609
3685
|
},
|
|
3610
3686
|
children: [
|
|
3611
|
-
/* @__PURE__ */
|
|
3612
|
-
isDual && cameraPlaybackUrl && /* @__PURE__ */
|
|
3687
|
+
/* @__PURE__ */ jsx5("a", { href: playbackUrl, download: downloadFilename, style: btnSecondary, children: isDual ? "Download screen recording" : "Download recording" }),
|
|
3688
|
+
isDual && cameraPlaybackUrl && /* @__PURE__ */ jsx5(
|
|
3613
3689
|
"a",
|
|
3614
3690
|
{
|
|
3615
3691
|
href: cameraPlaybackUrl,
|
|
@@ -3623,7 +3699,7 @@ function RecorderModal({
|
|
|
3623
3699
|
children: "Download camera recording"
|
|
3624
3700
|
}
|
|
3625
3701
|
),
|
|
3626
|
-
timingDownloadUrl && /* @__PURE__ */
|
|
3702
|
+
timingDownloadUrl && /* @__PURE__ */ jsx5(
|
|
3627
3703
|
"a",
|
|
3628
3704
|
{
|
|
3629
3705
|
href: timingDownloadUrl,
|
|
@@ -3636,8 +3712,8 @@ function RecorderModal({
|
|
|
3636
3712
|
}
|
|
3637
3713
|
),
|
|
3638
3714
|
!narrationOn && !slidesTimingCapture && source === "mic" && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3639
|
-
/* @__PURE__ */
|
|
3640
|
-
/* @__PURE__ */
|
|
3715
|
+
/* @__PURE__ */ jsx5("label", { style: labelStyle, htmlFor: "recorder-source-text", children: "Script (used to auto-match this narration to a block)" }),
|
|
3716
|
+
/* @__PURE__ */ jsx5(
|
|
3641
3717
|
"textarea",
|
|
3642
3718
|
{
|
|
3643
3719
|
id: "recorder-source-text",
|
|
@@ -3649,8 +3725,8 @@ function RecorderModal({
|
|
|
3649
3725
|
}
|
|
3650
3726
|
)
|
|
3651
3727
|
] }),
|
|
3652
|
-
/* @__PURE__ */
|
|
3653
|
-
/* @__PURE__ */
|
|
3728
|
+
/* @__PURE__ */ jsx5("label", { style: labelStyle, htmlFor: "recorder-basename", children: "Filename (optional)" }),
|
|
3729
|
+
/* @__PURE__ */ jsx5(
|
|
3654
3730
|
"input",
|
|
3655
3731
|
{
|
|
3656
3732
|
id: "recorder-basename",
|
|
@@ -3668,7 +3744,7 @@ function RecorderModal({
|
|
|
3668
3744
|
] }),
|
|
3669
3745
|
showTimingCheckbox && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3670
3746
|
/* @__PURE__ */ jsxs5("label", { style: checkboxRowStyle, children: [
|
|
3671
|
-
/* @__PURE__ */
|
|
3747
|
+
/* @__PURE__ */ jsx5(
|
|
3672
3748
|
"input",
|
|
3673
3749
|
{
|
|
3674
3750
|
type: "checkbox",
|
|
@@ -3680,10 +3756,10 @@ function RecorderModal({
|
|
|
3680
3756
|
),
|
|
3681
3757
|
SLIDE_TIMING_CHECKBOX_LABEL
|
|
3682
3758
|
] }),
|
|
3683
|
-
applySlideTimings && slideCoverageWarning && /* @__PURE__ */
|
|
3759
|
+
applySlideTimings && slideCoverageWarning && /* @__PURE__ */ jsx5("p", { style: summaryStyle, children: slideCoverageWarning })
|
|
3684
3760
|
] }),
|
|
3685
3761
|
/* @__PURE__ */ jsxs5("div", { style: buttonRowStyle, children: [
|
|
3686
|
-
/* @__PURE__ */
|
|
3762
|
+
/* @__PURE__ */ jsx5(
|
|
3687
3763
|
"button",
|
|
3688
3764
|
{
|
|
3689
3765
|
type: "button",
|
|
@@ -3694,7 +3770,7 @@ function RecorderModal({
|
|
|
3694
3770
|
}
|
|
3695
3771
|
),
|
|
3696
3772
|
narrationRecording && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3697
|
-
narrationRecorderIdle && !narrationMicLive && /* @__PURE__ */
|
|
3773
|
+
narrationRecorderIdle && !narrationMicLive && /* @__PURE__ */ jsx5(
|
|
3698
3774
|
"button",
|
|
3699
3775
|
{
|
|
3700
3776
|
type: "button",
|
|
@@ -3705,13 +3781,13 @@ function RecorderModal({
|
|
|
3705
3781
|
}
|
|
3706
3782
|
),
|
|
3707
3783
|
narrationRecorderIdle && narrationMicLive && /* @__PURE__ */ jsxs5("button", { type: "button", style: btnRecord, onClick: handleNarrationRecord, children: [
|
|
3708
|
-
/* @__PURE__ */
|
|
3784
|
+
/* @__PURE__ */ jsx5(
|
|
3709
3785
|
"span",
|
|
3710
3786
|
{
|
|
3711
3787
|
className: "squisq-recorder-record-dot",
|
|
3712
3788
|
style: recordDotFrameStyle,
|
|
3713
3789
|
"aria-hidden": "true",
|
|
3714
|
-
children: /* @__PURE__ */
|
|
3790
|
+
children: /* @__PURE__ */ jsx5(
|
|
3715
3791
|
"span",
|
|
3716
3792
|
{
|
|
3717
3793
|
className: "squisq-recorder-record-dot-center",
|
|
@@ -3722,7 +3798,7 @@ function RecorderModal({
|
|
|
3722
3798
|
),
|
|
3723
3799
|
"Record"
|
|
3724
3800
|
] }),
|
|
3725
|
-
(stage.recorder.state === "recording" || stage.recorder.state === "starting") && /* @__PURE__ */
|
|
3801
|
+
(stage.recorder.state === "recording" || stage.recorder.state === "starting") && /* @__PURE__ */ jsx5(
|
|
3726
3802
|
"button",
|
|
3727
3803
|
{
|
|
3728
3804
|
type: "button",
|
|
@@ -3731,11 +3807,11 @@ function RecorderModal({
|
|
|
3731
3807
|
children: "Stop"
|
|
3732
3808
|
}
|
|
3733
3809
|
),
|
|
3734
|
-
stage.recorder.state === "processing" && /* @__PURE__ */
|
|
3735
|
-
stage.recorder.state === "saving" && /* @__PURE__ */
|
|
3810
|
+
stage.recorder.state === "processing" && /* @__PURE__ */ jsx5("span", { style: recordingStatusStyle, children: "Aligning take\u2026" }),
|
|
3811
|
+
stage.recorder.state === "saving" && /* @__PURE__ */ jsx5("span", { style: recordingStatusStyle, children: "Saving\u2026" }),
|
|
3736
3812
|
stage.recorder.state === "review" && stage.recorder.take && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3737
|
-
/* @__PURE__ */
|
|
3738
|
-
/* @__PURE__ */
|
|
3813
|
+
/* @__PURE__ */ jsx5("button", { type: "button", style: btnSecondary, onClick: stage.handleRetake, children: "Discard & re-record" }),
|
|
3814
|
+
/* @__PURE__ */ jsx5(
|
|
3739
3815
|
"button",
|
|
3740
3816
|
{
|
|
3741
3817
|
type: "button",
|
|
@@ -3747,7 +3823,7 @@ function RecorderModal({
|
|
|
3747
3823
|
] })
|
|
3748
3824
|
] }),
|
|
3749
3825
|
!narrationRecording && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3750
|
-
(recorder.state === "idle" || recorder.state === "error" || recorder.state === "requesting") && /* @__PURE__ */
|
|
3826
|
+
(recorder.state === "idle" || recorder.state === "error" || recorder.state === "requesting") && /* @__PURE__ */ jsx5(
|
|
3751
3827
|
"button",
|
|
3752
3828
|
{
|
|
3753
3829
|
type: "button",
|
|
@@ -3765,13 +3841,13 @@ function RecorderModal({
|
|
|
3765
3841
|
onClick: () => void handleStart(),
|
|
3766
3842
|
disabled: isBusy,
|
|
3767
3843
|
children: [
|
|
3768
|
-
/* @__PURE__ */
|
|
3844
|
+
/* @__PURE__ */ jsx5(
|
|
3769
3845
|
"span",
|
|
3770
3846
|
{
|
|
3771
3847
|
className: "squisq-recorder-record-dot",
|
|
3772
3848
|
style: recordDotFrameStyle,
|
|
3773
3849
|
"aria-hidden": "true",
|
|
3774
|
-
children: /* @__PURE__ */
|
|
3850
|
+
children: /* @__PURE__ */ jsx5(
|
|
3775
3851
|
"span",
|
|
3776
3852
|
{
|
|
3777
3853
|
className: "squisq-recorder-record-dot-center",
|
|
@@ -3784,9 +3860,9 @@ function RecorderModal({
|
|
|
3784
3860
|
]
|
|
3785
3861
|
}
|
|
3786
3862
|
),
|
|
3787
|
-
canStop && /* @__PURE__ */
|
|
3863
|
+
canStop && /* @__PURE__ */ jsx5("button", { type: "button", style: btnDanger, onClick: handleStop, disabled: isBusy, children: "Stop" }),
|
|
3788
3864
|
canSave && /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
3789
|
-
/* @__PURE__ */
|
|
3865
|
+
/* @__PURE__ */ jsx5(
|
|
3790
3866
|
"button",
|
|
3791
3867
|
{
|
|
3792
3868
|
type: "button",
|
|
@@ -3796,7 +3872,7 @@ function RecorderModal({
|
|
|
3796
3872
|
children: "Discard & re-record"
|
|
3797
3873
|
}
|
|
3798
3874
|
),
|
|
3799
|
-
/* @__PURE__ */
|
|
3875
|
+
/* @__PURE__ */ jsx5(
|
|
3800
3876
|
"button",
|
|
3801
3877
|
{
|
|
3802
3878
|
type: "button",
|
|
@@ -3812,7 +3888,7 @@ function RecorderModal({
|
|
|
3812
3888
|
]
|
|
3813
3889
|
}
|
|
3814
3890
|
),
|
|
3815
|
-
narrationOn && narration && /* @__PURE__ */
|
|
3891
|
+
narrationOn && narration && /* @__PURE__ */ jsx5("div", { style: { ...rightColStyle, flex: "1 1 0" }, children: /* @__PURE__ */ jsx5(
|
|
3816
3892
|
NarrationStage,
|
|
3817
3893
|
{
|
|
3818
3894
|
stage,
|
|
@@ -3824,7 +3900,7 @@ function RecorderModal({
|
|
|
3824
3900
|
showReviewActions: false
|
|
3825
3901
|
}
|
|
3826
3902
|
) }),
|
|
3827
|
-
slidesOn && /* @__PURE__ */
|
|
3903
|
+
slidesOn && /* @__PURE__ */ jsx5("div", { style: { ...rightColStyle, flex: "1 1 0" }, children: /* @__PURE__ */ jsx5(
|
|
3828
3904
|
RecorderSlidesPanel,
|
|
3829
3905
|
{
|
|
3830
3906
|
slides: slideDeck,
|
|
@@ -3847,9 +3923,9 @@ function RecorderModal({
|
|
|
3847
3923
|
}
|
|
3848
3924
|
|
|
3849
3925
|
// src/recorder/RecorderPanel.tsx
|
|
3850
|
-
import { useCallback as useCallback5, useState as
|
|
3926
|
+
import { useCallback as useCallback5, useState as useState5 } from "react";
|
|
3851
3927
|
import { createPortal } from "react-dom";
|
|
3852
|
-
import { Fragment as Fragment4, jsx as
|
|
3928
|
+
import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3853
3929
|
function RecorderPanel({
|
|
3854
3930
|
mediaProvider,
|
|
3855
3931
|
container = null,
|
|
@@ -3865,7 +3941,7 @@ function RecorderPanel({
|
|
|
3865
3941
|
onOpenChange,
|
|
3866
3942
|
showTrigger = true
|
|
3867
3943
|
}) {
|
|
3868
|
-
const [uncontrolledOpen, setUncontrolledOpen] =
|
|
3944
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState5(false);
|
|
3869
3945
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
3870
3946
|
const setOpen = useCallback5(
|
|
3871
3947
|
(nextOpen) => {
|
|
@@ -3876,7 +3952,7 @@ function RecorderPanel({
|
|
|
3876
3952
|
);
|
|
3877
3953
|
const handleClose = useCallback5(() => setOpen(false), [setOpen]);
|
|
3878
3954
|
return /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3879
|
-
showTrigger && /* @__PURE__ */
|
|
3955
|
+
showTrigger && /* @__PURE__ */ jsx6(
|
|
3880
3956
|
"button",
|
|
3881
3957
|
{
|
|
3882
3958
|
type: "button",
|
|
@@ -3885,11 +3961,11 @@ function RecorderPanel({
|
|
|
3885
3961
|
"aria-label": tooltip,
|
|
3886
3962
|
"aria-expanded": open,
|
|
3887
3963
|
onClick: () => setOpen(!open),
|
|
3888
|
-
children: /* @__PURE__ */
|
|
3964
|
+
children: /* @__PURE__ */ jsx6(Icon, { icon: "fa-solid fa-microphone" })
|
|
3889
3965
|
}
|
|
3890
3966
|
),
|
|
3891
3967
|
open && typeof document !== "undefined" && createPortal(
|
|
3892
|
-
/* @__PURE__ */
|
|
3968
|
+
/* @__PURE__ */ jsx6(
|
|
3893
3969
|
RecorderModal,
|
|
3894
3970
|
{
|
|
3895
3971
|
mediaProvider,
|
|
@@ -3932,7 +4008,6 @@ export {
|
|
|
3932
4008
|
documentTitleFromFileName,
|
|
3933
4009
|
resolveBlockVisual,
|
|
3934
4010
|
buildRecorderSlideDeck,
|
|
3935
|
-
BlockThumbnail,
|
|
3936
4011
|
RecorderSlidesPanel,
|
|
3937
4012
|
useModalDialog,
|
|
3938
4013
|
RecorderModal,
|