@taskp3/react 0.2.0 → 0.2.2
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/recorder/capture.d.ts.map +1 -1
- package/dist/recorder/capture.js +10 -2
- package/dist/recorder/capture.js.map +1 -1
- package/dist/recorder/composeRecordingWithCamera.d.ts.map +1 -1
- package/dist/recorder/composeRecordingWithCamera.js +8 -2
- package/dist/recorder/composeRecordingWithCamera.js.map +1 -1
- package/dist/recorder/finalize-recording-worker-source.d.ts +1 -1
- package/dist/recorder/finalize-recording-worker-source.d.ts.map +1 -1
- package/dist/recorder/finalize-recording-worker-source.js +1 -1
- package/dist/recorder/finalize-recording-worker-source.js.map +1 -1
- package/dist/recorder/finalizeRecording.d.ts.map +1 -1
- package/dist/recorder/finalizeRecording.js +5 -3
- package/dist/recorder/finalizeRecording.js.map +1 -1
- package/dist/recorder/live-camera-overlay.d.ts +7 -0
- package/dist/recorder/live-camera-overlay.d.ts.map +1 -0
- package/dist/recorder/live-camera-overlay.js +172 -0
- package/dist/recorder/live-camera-overlay.js.map +1 -0
- package/dist/screen-recorder-context.d.ts +1 -0
- package/dist/screen-recorder-context.d.ts.map +1 -1
- package/dist/screen-recorder-context.js +56 -11
- package/dist/screen-recorder-context.js.map +1 -1
- package/dist/screen-recorder.d.ts.map +1 -1
- package/dist/screen-recorder.js +40 -66
- package/dist/screen-recorder.js.map +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +85 -0
- package/dist/styles.js.map +1 -1
- package/dist/use-recorder-controller.d.ts.map +1 -1
- package/dist/use-recorder-controller.js +19 -69
- package/dist/use-recorder-controller.js.map +1 -1
- package/package.json +1 -1
package/dist/screen-recorder.js
CHANGED
|
@@ -41,51 +41,12 @@ const use_recorder_controller_1 = require("./use-recorder-controller");
|
|
|
41
41
|
const screen_recorder_context_1 = require("./screen-recorder-context");
|
|
42
42
|
const icons_1 = require("./icons");
|
|
43
43
|
const recorder_preview_player_1 = require("./recorder-preview-player");
|
|
44
|
+
const live_camera_overlay_1 = require("./recorder/live-camera-overlay");
|
|
44
45
|
function formatTime(seconds) {
|
|
45
46
|
const m = Math.floor(seconds / 60);
|
|
46
47
|
const s = seconds % 60;
|
|
47
48
|
return `${m}:${s.toString().padStart(2, "0")}`;
|
|
48
49
|
}
|
|
49
|
-
function LiveCameraPreview({ stream, pipWidth, }) {
|
|
50
|
-
const videoRef = react_1.default.useRef(null);
|
|
51
|
-
(0, react_1.useEffect)(() => {
|
|
52
|
-
const video = videoRef.current;
|
|
53
|
-
if (!video)
|
|
54
|
-
return;
|
|
55
|
-
video.srcObject = stream;
|
|
56
|
-
if (stream) {
|
|
57
|
-
video.play().catch(() => { });
|
|
58
|
-
}
|
|
59
|
-
return () => {
|
|
60
|
-
if (video.srcObject === stream) {
|
|
61
|
-
video.srcObject = null;
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
}, [stream]);
|
|
65
|
-
if (!stream) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
69
|
-
position: "fixed",
|
|
70
|
-
left: 16,
|
|
71
|
-
bottom: 76,
|
|
72
|
-
zIndex: 2147483647,
|
|
73
|
-
width: pipWidth,
|
|
74
|
-
maxWidth: 180,
|
|
75
|
-
aspectRatio: "1 / 1",
|
|
76
|
-
overflow: "hidden",
|
|
77
|
-
borderRadius: 999,
|
|
78
|
-
border: "2px solid rgba(255,255,255,0.72)",
|
|
79
|
-
background: "#000",
|
|
80
|
-
boxShadow: "0 10px 26px rgba(0,0,0,0.24)",
|
|
81
|
-
}, children: (0, jsx_runtime_1.jsx)("video", { ref: videoRef, muted: true, playsInline: true, autoPlay: true, style: {
|
|
82
|
-
display: "block",
|
|
83
|
-
width: "100%",
|
|
84
|
-
height: "100%",
|
|
85
|
-
objectFit: "cover",
|
|
86
|
-
transform: "scaleX(-1)",
|
|
87
|
-
} }) }));
|
|
88
|
-
}
|
|
89
50
|
const FIXED_BAR_STYLE = {
|
|
90
51
|
position: "fixed",
|
|
91
52
|
bottom: 16,
|
|
@@ -93,10 +54,15 @@ const FIXED_BAR_STYLE = {
|
|
|
93
54
|
zIndex: 2147483647,
|
|
94
55
|
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
95
56
|
};
|
|
57
|
+
function RecorderSetupPill({ microphoneEnabled, cameraEnabled, microphoneError, cameraError, error, onMicrophoneEnabledChange, onCameraEnabledChange, onStart, onCancel, }) {
|
|
58
|
+
const generalError = error && error !== microphoneError && error !== cameraError ? error : null;
|
|
59
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: FIXED_BAR_STYLE, className: "p3-rec-bar-wrapper", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p3-rec-bar p3-rec-bar--setup", children: [(0, jsx_runtime_1.jsx)("span", { className: "p3-rec-setup-title", children: "Record screen" }), (0, jsx_runtime_1.jsxs)("label", { className: `p3-rec-option ${microphoneEnabled ? "p3-rec-option--on" : "p3-rec-option--off"}`, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: microphoneEnabled, onChange: (event) => onMicrophoneEnabledChange(event.target.checked) }), (0, jsx_runtime_1.jsx)("span", { children: "Mic" }), (0, jsx_runtime_1.jsx)("span", { className: "p3-rec-option-state", children: microphoneEnabled ? "On" : "Off" })] }), (0, jsx_runtime_1.jsxs)("label", { className: `p3-rec-option ${cameraEnabled ? "p3-rec-option--on" : "p3-rec-option--off"}`, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: cameraEnabled, onChange: (event) => onCameraEnabledChange(event.target.checked) }), (0, jsx_runtime_1.jsx)("span", { children: "Camera" }), (0, jsx_runtime_1.jsx)("span", { className: "p3-rec-option-state", children: cameraEnabled ? "On" : "Off" })] }), (0, jsx_runtime_1.jsxs)("span", { className: "p3-rec-controls", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-rec-start", onClick: onStart, children: "Start" }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-rec-ctrl p3-rec-ctrl--danger", onClick: onCancel, "aria-label": "Cancel recording setup", "data-tooltip": "Cancel", children: (0, jsx_runtime_1.jsx)(icons_1.TrashIcon, { size: 12 }) })] })] }), microphoneEnabled && microphoneError && ((0, jsx_runtime_1.jsx)("p", { className: "p3-rec-error", children: microphoneError.message })), cameraEnabled && cameraError && ((0, jsx_runtime_1.jsx)("p", { className: "p3-rec-error", children: cameraError.message })), generalError && ((0, jsx_runtime_1.jsx)("p", { className: "p3-rec-error", children: generalError.message }))] }));
|
|
60
|
+
}
|
|
96
61
|
exports.ScreenRecorder = react_1.default.forwardRef(function ScreenRecorder({ onAttach, onMicrophoneErrorChange, hideIdleTrigger = false, target = "submission", ...opts }, ref) {
|
|
97
62
|
const ctx = (0, screen_recorder_context_1.useScreenRecorderContext)();
|
|
98
63
|
const localRecorder = (0, use_recorder_controller_1.useRecorderController)(opts);
|
|
99
64
|
const [isAttaching, setIsAttaching] = (0, react_1.useState)(false);
|
|
65
|
+
const [isConfiguring, setIsConfiguring] = (0, react_1.useState)(false);
|
|
100
66
|
const recorder = ctx?.recorder ?? localRecorder;
|
|
101
67
|
const useGlobalUI = ctx != null;
|
|
102
68
|
(0, react_1.useEffect)(() => {
|
|
@@ -105,14 +71,32 @@ exports.ScreenRecorder = react_1.default.forwardRef(function ScreenRecorder({ on
|
|
|
105
71
|
ctx.setOnAttach(onAttach);
|
|
106
72
|
ctx.setTargetOnAttach(target, onAttach);
|
|
107
73
|
}, [useGlobalUI, onAttach, ctx, target]);
|
|
108
|
-
const
|
|
74
|
+
const openRecorderSetup = (0, react_1.useCallback)(async () => {
|
|
109
75
|
ctx?.setActiveTarget(target);
|
|
110
|
-
|
|
111
|
-
|
|
76
|
+
if (ctx) {
|
|
77
|
+
ctx.openStartOptions(target);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
setIsConfiguring(true);
|
|
81
|
+
}, [ctx, target]);
|
|
82
|
+
const startRecording = (0, react_1.useCallback)(() => {
|
|
83
|
+
void recorder.start();
|
|
84
|
+
}, [recorder]);
|
|
85
|
+
const cancelRecorderSetup = (0, react_1.useCallback)(() => {
|
|
86
|
+
setIsConfiguring(false);
|
|
87
|
+
if (recorder.state === "error") {
|
|
88
|
+
recorder.discard();
|
|
89
|
+
}
|
|
90
|
+
}, [recorder]);
|
|
112
91
|
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
113
|
-
start:
|
|
114
|
-
}), [
|
|
92
|
+
start: openRecorderSetup,
|
|
93
|
+
}), [openRecorderSetup]);
|
|
115
94
|
const { state, duration, previewUrl, cameraPreviewUrl, liveCameraStream, error, microphoneError, cameraError, isSupported, microphoneEnabled, cameraEnabled, setMicrophoneEnabled, setCameraEnabled, stop, pause, resume, restart, discard, isFinalizing, ensureFinalizedBlob, } = recorder;
|
|
95
|
+
(0, react_1.useEffect)(() => {
|
|
96
|
+
if (state !== "idle" && state !== "error" && state !== "requesting") {
|
|
97
|
+
setIsConfiguring(false);
|
|
98
|
+
}
|
|
99
|
+
}, [state]);
|
|
116
100
|
(0, react_1.useEffect)(() => {
|
|
117
101
|
onMicrophoneErrorChange?.(microphoneError);
|
|
118
102
|
}, [microphoneError, onMicrophoneErrorChange]);
|
|
@@ -135,30 +119,20 @@ exports.ScreenRecorder = react_1.default.forwardRef(function ScreenRecorder({ on
|
|
|
135
119
|
if (!isSupported)
|
|
136
120
|
return null;
|
|
137
121
|
if (state === "idle" || state === "error") {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
color: "#334155",
|
|
145
|
-
}, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: microphoneEnabled, onChange: (event) => setMicrophoneEnabled(event.target.checked) }), "Record microphone audio"] }), (0, jsx_runtime_1.jsxs)("label", { style: {
|
|
146
|
-
display: "flex",
|
|
147
|
-
alignItems: "center",
|
|
148
|
-
gap: 8,
|
|
149
|
-
marginBottom: 8,
|
|
150
|
-
fontSize: 13,
|
|
151
|
-
color: "#334155",
|
|
152
|
-
}, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: cameraEnabled, onChange: (event) => setCameraEnabled(event.target.checked) }), "Record camera overlay"] }), !hideIdleTrigger && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-icon-btn", onClick: startRecording, "aria-label": "Start screen recording", title: "Start screen recording", children: (0, jsx_runtime_1.jsx)(icons_1.VideoCameraFrontOutlinedIcon, { size: 16 }) })), microphoneEnabled && microphoneError && ((0, jsx_runtime_1.jsx)("p", { className: "p3-rec-error", children: microphoneError.message })), cameraEnabled && cameraError && ((0, jsx_runtime_1.jsx)("p", { className: "p3-rec-error", children: cameraError.message })), error && error !== microphoneError && ((0, jsx_runtime_1.jsx)("p", { className: "p3-rec-error", children: error.message }))] }));
|
|
122
|
+
if (useGlobalUI)
|
|
123
|
+
return null;
|
|
124
|
+
const setupPill = isConfiguring ? ((0, jsx_runtime_1.jsx)(RecorderSetupPill, { microphoneEnabled: microphoneEnabled, cameraEnabled: cameraEnabled, microphoneError: microphoneError, cameraError: cameraError, error: error, onMicrophoneEnabledChange: setMicrophoneEnabled, onCameraEnabledChange: setCameraEnabled, onStart: startRecording, onCancel: cancelRecorderSetup })) : null;
|
|
125
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "p3-rec", children: [!hideIdleTrigger && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-icon-btn", onClick: () => void openRecorderSetup(), "aria-label": "Start screen recording", title: "Start screen recording", children: (0, jsx_runtime_1.jsx)(icons_1.VideoCameraFrontOutlinedIcon, { size: 16 }) })), typeof document !== "undefined" && document.body && setupPill
|
|
126
|
+
? (0, react_dom_1.createPortal)(setupPill, document.body)
|
|
127
|
+
: setupPill] }));
|
|
153
128
|
}
|
|
154
|
-
if (
|
|
129
|
+
if (useGlobalUI) {
|
|
155
130
|
return null;
|
|
156
131
|
}
|
|
157
132
|
if (state === "requesting") {
|
|
158
|
-
|
|
133
|
+
const requestingContent = ((0, jsx_runtime_1.jsx)("div", { style: FIXED_BAR_STYLE, className: "p3-rec-bar-wrapper", children: (0, jsx_runtime_1.jsx)("div", { className: "p3-rec-bar p3-rec-bar--setup", children: (0, jsx_runtime_1.jsx)("span", { className: "p3-rec-setup-title", children: "Starting recording..." }) }) }));
|
|
134
|
+
return typeof document !== "undefined" && document.body ? ((0, react_dom_1.createPortal)(requestingContent, document.body)) : ((0, jsx_runtime_1.jsx)("div", { className: "p3-rec", children: requestingContent }));
|
|
159
135
|
}
|
|
160
|
-
if (useGlobalUI)
|
|
161
|
-
return null;
|
|
162
136
|
if (state === "recording" || state === "paused") {
|
|
163
137
|
const isPaused = state === "paused";
|
|
164
138
|
const barContent = ((0, jsx_runtime_1.jsx)("div", { style: FIXED_BAR_STYLE, className: "p3-rec-bar-wrapper", children: (0, jsx_runtime_1.jsxs)("div", { className: "p3-rec-bar", children: [(0, jsx_runtime_1.jsx)("span", { className: "p3-rec-dot", style: isPaused ? { animationPlayState: "paused", opacity: 0.4 } : undefined }), (0, jsx_runtime_1.jsx)("span", { className: "p3-rec-timer", children: formatTime(duration) }), (0, jsx_runtime_1.jsx)("span", { style: {
|
|
@@ -175,9 +149,9 @@ exports.ScreenRecorder = react_1.default.forwardRef(function ScreenRecorder({ on
|
|
|
175
149
|
padding: "2px 8px",
|
|
176
150
|
}, children: cameraEnabled ? "Cam on" : "Cam off" }), (0, jsx_runtime_1.jsxs)("span", { className: "p3-rec-controls", children: [isPaused ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-rec-ctrl", onClick: resume, "aria-label": "Resume", "data-tooltip": "Resume", children: (0, jsx_runtime_1.jsx)(icons_1.PlayIcon, { size: 12 }) })) : ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-rec-ctrl", onClick: pause, "aria-label": "Pause", "data-tooltip": "Pause", children: (0, jsx_runtime_1.jsx)(icons_1.PauseIcon, { size: 12 }) })), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-rec-ctrl", onClick: restart, "aria-label": "Restart", "data-tooltip": "Restart", children: (0, jsx_runtime_1.jsx)(icons_1.RestartIcon, { size: 12 }) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "p3-rec-ctrl p3-rec-ctrl--danger", onClick: discard, "aria-label": "Discard", "data-tooltip": "Discard", children: (0, jsx_runtime_1.jsx)(icons_1.TrashIcon, { size: 12 }) }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "p3-rec-stop", onClick: stop, children: [(0, jsx_runtime_1.jsx)(icons_1.StopCircleIcon, { size: 12 }), "Stop"] })] })] }) }));
|
|
177
151
|
if (typeof document !== "undefined" && document.body) {
|
|
178
|
-
return (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [cameraEnabled && (0, jsx_runtime_1.jsx)(
|
|
152
|
+
return (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [cameraEnabled && ((0, jsx_runtime_1.jsx)(live_camera_overlay_1.LiveCameraOverlay, { stream: liveCameraStream, pipScale: opts.pipScale })), barContent] }), document.body);
|
|
179
153
|
}
|
|
180
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "p3-rec", children: [cameraEnabled && (0, jsx_runtime_1.jsx)(
|
|
154
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "p3-rec", children: [cameraEnabled && ((0, jsx_runtime_1.jsx)(live_camera_overlay_1.LiveCameraOverlay, { stream: liveCameraStream, pipScale: opts.pipScale })), (0, jsx_runtime_1.jsx)("div", { className: "p3-rec-bar", children: barContent.props.children })] }));
|
|
181
155
|
}
|
|
182
156
|
if (state === "stopping") {
|
|
183
157
|
const processingContent = ((0, jsx_runtime_1.jsx)("div", { style: FIXED_BAR_STYLE, className: "p3-rec-bar-wrapper", children: (0, jsx_runtime_1.jsx)("div", { className: "p3-rec-bar", style: { background: "#f0f9ff", borderColor: "#bae6fd" }, children: (0, jsx_runtime_1.jsx)("span", { className: "p3-rec-timer", style: { color: "#0369a1" }, children: "Processing\u2026" }) }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen-recorder.js","sourceRoot":"","sources":["../src/screen-recorder.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAMe;AACf,yCAAyC;AACzC,uEAImC;AACnC,uEAAqE;AACrE,mCAQiB;AACjB,uEAAkE;
|
|
1
|
+
{"version":3,"file":"screen-recorder.js","sourceRoot":"","sources":["../src/screen-recorder.tsx"],"names":[],"mappings":"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"}
|
package/dist/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,CAy5B3D"}
|
package/dist/styles.js
CHANGED
|
@@ -345,6 +345,82 @@ function TRIAGE_CSS(t) {
|
|
|
345
345
|
background: #fef2f2;
|
|
346
346
|
border: 1px solid #fecaca;
|
|
347
347
|
}
|
|
348
|
+
.p3-rec-bar--setup {
|
|
349
|
+
background: #fef2f2;
|
|
350
|
+
border-color: #fecaca;
|
|
351
|
+
}
|
|
352
|
+
.p3-rec-setup-title {
|
|
353
|
+
font-size: 13px;
|
|
354
|
+
font-weight: 600;
|
|
355
|
+
color: #991b1b;
|
|
356
|
+
white-space: nowrap;
|
|
357
|
+
}
|
|
358
|
+
.p3-rec-option {
|
|
359
|
+
position: relative;
|
|
360
|
+
display: inline-flex;
|
|
361
|
+
align-items: center;
|
|
362
|
+
gap: 6px;
|
|
363
|
+
min-height: 28px;
|
|
364
|
+
padding: 4px 9px;
|
|
365
|
+
border: 1px solid transparent;
|
|
366
|
+
border-radius: 6px;
|
|
367
|
+
font-size: 12px;
|
|
368
|
+
font-weight: 600;
|
|
369
|
+
color: #991b1b;
|
|
370
|
+
white-space: nowrap;
|
|
371
|
+
cursor: pointer;
|
|
372
|
+
transition: background 0.12s;
|
|
373
|
+
}
|
|
374
|
+
.p3-rec-option:hover {
|
|
375
|
+
background: #fecaca;
|
|
376
|
+
}
|
|
377
|
+
.p3-rec-option--on {
|
|
378
|
+
background: #fee2e2;
|
|
379
|
+
border-color: #fca5a5;
|
|
380
|
+
}
|
|
381
|
+
.p3-rec-option--off {
|
|
382
|
+
color: #b45309;
|
|
383
|
+
background: rgba(255, 255, 255, 0.5);
|
|
384
|
+
border-color: #fecaca;
|
|
385
|
+
}
|
|
386
|
+
.p3-rec-option-state {
|
|
387
|
+
display: inline-flex;
|
|
388
|
+
align-items: center;
|
|
389
|
+
justify-content: center;
|
|
390
|
+
min-width: 22px;
|
|
391
|
+
padding: 1px 5px;
|
|
392
|
+
border-radius: 999px;
|
|
393
|
+
font-size: 10px;
|
|
394
|
+
font-weight: 700;
|
|
395
|
+
text-transform: uppercase;
|
|
396
|
+
letter-spacing: 0.02em;
|
|
397
|
+
}
|
|
398
|
+
.p3-rec-option--on .p3-rec-option-state {
|
|
399
|
+
background: #ef4444;
|
|
400
|
+
color: #fff;
|
|
401
|
+
}
|
|
402
|
+
.p3-rec-option--off .p3-rec-option-state {
|
|
403
|
+
background: #fff7ed;
|
|
404
|
+
color: #b45309;
|
|
405
|
+
}
|
|
406
|
+
.p3-rec-option input {
|
|
407
|
+
appearance: none;
|
|
408
|
+
width: 10px;
|
|
409
|
+
height: 10px;
|
|
410
|
+
margin: 0;
|
|
411
|
+
border-radius: 50%;
|
|
412
|
+
border: 1px solid #fca5a5;
|
|
413
|
+
background: #fee2e2;
|
|
414
|
+
}
|
|
415
|
+
.p3-rec-option input:checked {
|
|
416
|
+
border-color: #ef4444;
|
|
417
|
+
background: #ef4444;
|
|
418
|
+
box-shadow: 0 0 0 3px #fee2e2 inset;
|
|
419
|
+
}
|
|
420
|
+
.p3-rec-option input:focus-visible {
|
|
421
|
+
outline: 2px solid #fca5a5;
|
|
422
|
+
outline-offset: 2px;
|
|
423
|
+
}
|
|
348
424
|
.p3-rec-dot {
|
|
349
425
|
width: 10px; height: 10px;
|
|
350
426
|
border-radius: 50%;
|
|
@@ -409,6 +485,15 @@ function TRIAGE_CSS(t) {
|
|
|
409
485
|
cursor: pointer; transition: background 0.12s;
|
|
410
486
|
}
|
|
411
487
|
.p3-rec-stop:hover { background: #dc2626; }
|
|
488
|
+
.p3-rec-start {
|
|
489
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
490
|
+
padding: 4px 10px;
|
|
491
|
+
border: none; border-radius: 6px;
|
|
492
|
+
background: #16a34a; color: #fff;
|
|
493
|
+
font-family: ${t.fontFamily}; font-size: 12px; font-weight: 600;
|
|
494
|
+
cursor: pointer; transition: background 0.12s;
|
|
495
|
+
}
|
|
496
|
+
.p3-rec-start:hover { background: #15803d; }
|
|
412
497
|
|
|
413
498
|
.p3-rec-preview {
|
|
414
499
|
position: relative;
|
package/dist/styles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":";;AAEA,
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-recorder-controller.d.ts","sourceRoot":"","sources":["../src/use-recorder-controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"use-recorder-controller.d.ts","sourceRoot":"","sources":["../src/use-recorder-controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAChC,MAAM,8BAA8B,CAAC;AAGtC,YAAY,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,UAAU,GACV,SAAS,GACT,OAAO,CAAC;AA4BZ,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,eAAe,EAAE,KAAK,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,gBAAgB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,0BAA0B,GAAG,IAAI,CAAC;IACzD,mBAAmB,EAAE,MAAM,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAAC;CACrE;AAuOD,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,yBAA8B,GACtC,wBAAwB,CA8d1B"}
|
|
@@ -9,10 +9,13 @@ exports.useRecorderController = useRecorderController;
|
|
|
9
9
|
const react_1 = require("react");
|
|
10
10
|
const finalizeRecordingInWorker_1 = require("./recorder/finalizeRecordingInWorker");
|
|
11
11
|
const DEFAULT_MAX_MS = 5 * 60 * 1000;
|
|
12
|
-
const
|
|
12
|
+
const DEFAULT_VIDEO_BITRATE = 1000000;
|
|
13
13
|
const MIME = typeof MediaRecorder !== "undefined" && MediaRecorder.isTypeSupported("video/webm;codecs=vp9")
|
|
14
14
|
? "video/webm;codecs=vp9"
|
|
15
15
|
: "video/webm";
|
|
16
|
+
const CAMERA_WIDTH = 320;
|
|
17
|
+
const CAMERA_HEIGHT = 240;
|
|
18
|
+
const CAMERA_FRAME_RATE = 15;
|
|
16
19
|
function isSupported() {
|
|
17
20
|
return (typeof window !== "undefined" &&
|
|
18
21
|
typeof MediaRecorder !== "undefined" &&
|
|
@@ -96,7 +99,12 @@ async function tryAcquireCamera(required) {
|
|
|
96
99
|
throw createCameraCaptureError("Camera recording is enabled, but no camera device was found. Connect a camera, make sure Firefox can see it, or turn off camera recording.");
|
|
97
100
|
}
|
|
98
101
|
const cameraStream = await navigator.mediaDevices.getUserMedia({
|
|
99
|
-
video:
|
|
102
|
+
video: {
|
|
103
|
+
width: { ideal: CAMERA_WIDTH, max: CAMERA_WIDTH },
|
|
104
|
+
height: { ideal: CAMERA_HEIGHT, max: CAMERA_HEIGHT },
|
|
105
|
+
frameRate: { ideal: CAMERA_FRAME_RATE, max: CAMERA_FRAME_RATE },
|
|
106
|
+
facingMode: "user",
|
|
107
|
+
},
|
|
100
108
|
audio: false,
|
|
101
109
|
});
|
|
102
110
|
const cameraTrack = cameraStream.getVideoTracks()[0];
|
|
@@ -106,8 +114,9 @@ async function tryAcquireCamera(required) {
|
|
|
106
114
|
}
|
|
107
115
|
cameraTrack
|
|
108
116
|
.applyConstraints({
|
|
109
|
-
width: { ideal:
|
|
110
|
-
height: { ideal:
|
|
117
|
+
width: { ideal: CAMERA_WIDTH, max: CAMERA_WIDTH },
|
|
118
|
+
height: { ideal: CAMERA_HEIGHT, max: CAMERA_HEIGHT },
|
|
119
|
+
frameRate: { ideal: CAMERA_FRAME_RATE, max: CAMERA_FRAME_RATE },
|
|
111
120
|
})
|
|
112
121
|
.catch(() => { });
|
|
113
122
|
return cameraStream;
|
|
@@ -180,7 +189,7 @@ function getFinalizationHints(displayStream, microphoneStream, cameraEnabled, pi
|
|
|
180
189
|
};
|
|
181
190
|
}
|
|
182
191
|
function useRecorderController(options = {}) {
|
|
183
|
-
const { maxDurationMs = DEFAULT_MAX_MS, videoBitsPerSecond =
|
|
192
|
+
const { maxDurationMs = DEFAULT_MAX_MS, videoBitsPerSecond = DEFAULT_VIDEO_BITRATE, defaultMicrophoneEnabled = true, microphoneEnabled: controlledMicrophoneEnabled, defaultCameraEnabled = false, cameraEnabled: controlledCameraEnabled, pipPosition = "bottom-right", pipShape = "circle", } = options;
|
|
184
193
|
const [state, setState] = (0, react_1.useState)("idle");
|
|
185
194
|
const [duration, setDuration] = (0, react_1.useState)(0);
|
|
186
195
|
const [previewUrl, setPreviewUrl] = (0, react_1.useState)(null);
|
|
@@ -210,9 +219,7 @@ function useRecorderController(options = {}) {
|
|
|
210
219
|
const cameraStreamRef = (0, react_1.useRef)(null);
|
|
211
220
|
const releaseAudioRef = (0, react_1.useRef)(null);
|
|
212
221
|
const recorderRef = (0, react_1.useRef)(null);
|
|
213
|
-
const cameraRecorderRef = (0, react_1.useRef)(null);
|
|
214
222
|
const chunksRef = (0, react_1.useRef)([]);
|
|
215
|
-
const cameraChunksRef = (0, react_1.useRef)([]);
|
|
216
223
|
const blobRef = (0, react_1.useRef)(null);
|
|
217
224
|
const blobMetadataRef = (0, react_1.useRef)(null);
|
|
218
225
|
const finalizePromiseRef = (0, react_1.useRef)(null);
|
|
@@ -243,7 +250,6 @@ function useRecorderController(options = {}) {
|
|
|
243
250
|
releaseAudioRef.current?.();
|
|
244
251
|
releaseAudioRef.current = null;
|
|
245
252
|
recorderRef.current = null;
|
|
246
|
-
cameraRecorderRef.current = null;
|
|
247
253
|
setLiveCameraStream(null);
|
|
248
254
|
}, []);
|
|
249
255
|
const buildFallbackMetadata = (0, react_1.useCallback)((blob, conversionReason) => ({
|
|
@@ -316,31 +322,19 @@ function useRecorderController(options = {}) {
|
|
|
316
322
|
releaseAudioRef.current = release;
|
|
317
323
|
streamRef.current = stream;
|
|
318
324
|
setLiveCameraStream(cameraStream ? new MediaStream(cameraStream.getVideoTracks()) : null);
|
|
319
|
-
const recorder = createVideoRecorder(stream, videoBitsPerSecond ??
|
|
320
|
-
const cameraRecorder = cameraStream && cameraStream.getVideoTracks().length > 0
|
|
321
|
-
? createVideoRecorder(new MediaStream(cameraStream.getVideoTracks()), cameraBitsPerSecond)
|
|
322
|
-
: null;
|
|
325
|
+
const recorder = createVideoRecorder(stream, videoBitsPerSecond ?? DEFAULT_VIDEO_BITRATE);
|
|
323
326
|
recorderRef.current = recorder;
|
|
324
|
-
cameraRecorderRef.current = cameraRecorder;
|
|
325
327
|
chunksRef.current = [];
|
|
326
|
-
cameraChunksRef.current = [];
|
|
327
328
|
recorder.ondataavailable = (e) => {
|
|
328
329
|
if (discardingRef.current)
|
|
329
330
|
return;
|
|
330
331
|
if (e.data.size > 0)
|
|
331
332
|
chunksRef.current.push(e.data);
|
|
332
333
|
};
|
|
333
|
-
cameraRecorder?.addEventListener("dataavailable", (e) => {
|
|
334
|
-
if (discardingRef.current)
|
|
335
|
-
return;
|
|
336
|
-
if (e.data.size > 0)
|
|
337
|
-
cameraChunksRef.current.push(e.data);
|
|
338
|
-
});
|
|
339
334
|
let screenStopped = false;
|
|
340
|
-
let cameraStopped = cameraRecorder == null;
|
|
341
335
|
let finalizationStarted = false;
|
|
342
336
|
const maybeFinalizeStoppedRecorders = async () => {
|
|
343
|
-
if (finalizationStarted || !screenStopped
|
|
337
|
+
if (finalizationStarted || !screenStopped) {
|
|
344
338
|
return;
|
|
345
339
|
}
|
|
346
340
|
finalizationStarted = true;
|
|
@@ -355,35 +349,20 @@ function useRecorderController(options = {}) {
|
|
|
355
349
|
const chunks = chunksRef.current;
|
|
356
350
|
const type = chunks[0]?.type || MIME.split(";")[0];
|
|
357
351
|
const rawBlob = new Blob(chunks, { type });
|
|
358
|
-
const cameraType = cameraChunksRef.current[0]?.type || cameraRecorder?.mimeType || MIME;
|
|
359
|
-
const rawCameraBlob = cameraChunksRef.current.length > 0
|
|
360
|
-
? new Blob(cameraChunksRef.current, { type: cameraType.split(";")[0] })
|
|
361
|
-
: null;
|
|
362
|
-
if (cameraEnabled && !rawCameraBlob) {
|
|
363
|
-
setError(new Error("Camera recording was enabled, but the camera overlay could not be captured."));
|
|
364
|
-
setState("error");
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
352
|
blobRef.current = rawBlob;
|
|
368
353
|
blobMetadataRef.current = {
|
|
369
354
|
...buildFallbackMetadata(rawBlob),
|
|
370
355
|
cameraOverlayEnabled: cameraEnabled || undefined,
|
|
371
|
-
cameraOverlayIncluded:
|
|
356
|
+
cameraOverlayIncluded: cameraEnabled || undefined,
|
|
372
357
|
cameraOverlayPosition: cameraEnabled ? pipPosition : undefined,
|
|
373
358
|
cameraOverlayShape: cameraEnabled ? pipShape : undefined,
|
|
374
359
|
};
|
|
375
360
|
setPreviewBlob(rawBlob);
|
|
376
|
-
setCameraPreviewBlob(
|
|
361
|
+
setCameraPreviewBlob(null);
|
|
377
362
|
setState("preview");
|
|
378
363
|
setIsFinalizing(true);
|
|
379
364
|
const runId = ++finalizationRunIdRef.current;
|
|
380
|
-
const finalizePromise = (0, finalizeRecordingInWorker_1.finalizeRecordingInWorker)(rawBlob, Math.max(elapsedMsRef.current, 1), finalizationHints
|
|
381
|
-
enabled: cameraEnabled,
|
|
382
|
-
cameraBlob: rawCameraBlob,
|
|
383
|
-
pipScale: options.pipScale,
|
|
384
|
-
position: pipPosition,
|
|
385
|
-
shape: pipShape,
|
|
386
|
-
});
|
|
365
|
+
const finalizePromise = (0, finalizeRecordingInWorker_1.finalizeRecordingInWorker)(rawBlob, Math.max(elapsedMsRef.current, 1), finalizationHints);
|
|
387
366
|
finalizePromiseRef.current = finalizePromise;
|
|
388
367
|
try {
|
|
389
368
|
const finalizedRecording = await finalizePromise;
|
|
@@ -426,17 +405,6 @@ function useRecorderController(options = {}) {
|
|
|
426
405
|
cleanup();
|
|
427
406
|
setState("error");
|
|
428
407
|
};
|
|
429
|
-
if (cameraRecorder) {
|
|
430
|
-
cameraRecorder.onstop = () => {
|
|
431
|
-
cameraStopped = true;
|
|
432
|
-
void maybeFinalizeStoppedRecorders();
|
|
433
|
-
};
|
|
434
|
-
cameraRecorder.onerror = () => {
|
|
435
|
-
setCameraError(new Error("Camera recording failed"));
|
|
436
|
-
cleanup();
|
|
437
|
-
setState("error");
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
408
|
displayStream.getVideoTracks()[0]?.addEventListener("ended", () => {
|
|
441
409
|
if (recorder.state === "recording") {
|
|
442
410
|
const activeMs = Date.now() - timerStartedAtRef.current;
|
|
@@ -446,7 +414,6 @@ function useRecorderController(options = {}) {
|
|
|
446
414
|
}
|
|
447
415
|
});
|
|
448
416
|
recorder.start();
|
|
449
|
-
cameraRecorder?.start();
|
|
450
417
|
remainingMaxMsRef.current = maxDurationMs;
|
|
451
418
|
elapsedMsRef.current = 0;
|
|
452
419
|
timerStartedAtRef.current = Date.now();
|
|
@@ -473,13 +440,11 @@ function useRecorderController(options = {}) {
|
|
|
473
440
|
setState("error");
|
|
474
441
|
}
|
|
475
442
|
}, [
|
|
476
|
-
cameraBitsPerSecond,
|
|
477
443
|
cameraEnabled,
|
|
478
444
|
buildFallbackMetadata,
|
|
479
445
|
cleanup,
|
|
480
446
|
maxDurationMs,
|
|
481
447
|
microphoneEnabled,
|
|
482
|
-
options.pipScale,
|
|
483
448
|
pipPosition,
|
|
484
449
|
pipShape,
|
|
485
450
|
scheduleMaxTimer,
|
|
@@ -504,25 +469,17 @@ function useRecorderController(options = {}) {
|
|
|
504
469
|
maxTimerRef.current = null;
|
|
505
470
|
}
|
|
506
471
|
const rec = recorderRef.current;
|
|
507
|
-
const cameraRec = cameraRecorderRef.current;
|
|
508
472
|
if (rec && (rec.state === "recording" || rec.state === "paused")) {
|
|
509
473
|
rec.requestData();
|
|
510
474
|
rec.stop();
|
|
511
475
|
}
|
|
512
|
-
if (cameraRec && (cameraRec.state === "recording" || cameraRec.state === "paused")) {
|
|
513
|
-
cameraRec.requestData();
|
|
514
|
-
cameraRec.stop();
|
|
515
|
-
}
|
|
516
476
|
}, [state]);
|
|
517
477
|
const pause = (0, react_1.useCallback)(() => {
|
|
518
478
|
if (state !== "recording")
|
|
519
479
|
return;
|
|
520
480
|
const rec = recorderRef.current;
|
|
521
|
-
const cameraRec = cameraRecorderRef.current;
|
|
522
481
|
if (rec?.state === "recording")
|
|
523
482
|
rec.pause();
|
|
524
|
-
if (cameraRec?.state === "recording")
|
|
525
|
-
cameraRec.pause();
|
|
526
483
|
if (timerRef.current) {
|
|
527
484
|
clearInterval(timerRef.current);
|
|
528
485
|
timerRef.current = null;
|
|
@@ -537,11 +494,8 @@ function useRecorderController(options = {}) {
|
|
|
537
494
|
if (state !== "paused")
|
|
538
495
|
return;
|
|
539
496
|
const rec = recorderRef.current;
|
|
540
|
-
const cameraRec = cameraRecorderRef.current;
|
|
541
497
|
if (rec?.state === "paused")
|
|
542
498
|
rec.resume();
|
|
543
|
-
if (cameraRec?.state === "paused")
|
|
544
|
-
cameraRec.resume();
|
|
545
499
|
timerStartedAtRef.current = Date.now();
|
|
546
500
|
timerRef.current = setInterval(() => {
|
|
547
501
|
const totalMs = elapsedMsRef.current + (Date.now() - timerStartedAtRef.current);
|
|
@@ -566,7 +520,6 @@ function useRecorderController(options = {}) {
|
|
|
566
520
|
elapsedMsRef.current = 0;
|
|
567
521
|
setState("idle");
|
|
568
522
|
const rec = recorderRef.current;
|
|
569
|
-
const cameraRec = cameraRecorderRef.current;
|
|
570
523
|
if (rec && (rec.state === "recording" || rec.state === "paused")) {
|
|
571
524
|
if (timerRef.current) {
|
|
572
525
|
clearInterval(timerRef.current);
|
|
@@ -577,9 +530,6 @@ function useRecorderController(options = {}) {
|
|
|
577
530
|
maxTimerRef.current = null;
|
|
578
531
|
}
|
|
579
532
|
rec.stop();
|
|
580
|
-
if (cameraRec && (cameraRec.state === "recording" || cameraRec.state === "paused")) {
|
|
581
|
-
cameraRec.stop();
|
|
582
|
-
}
|
|
583
533
|
return;
|
|
584
534
|
}
|
|
585
535
|
cleanup();
|