@qaiddev/thumbs-embed 1.6.0 → 1.6.1
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/chunks/{annotate-pSxJNPPL.js → annotate-NeITyYNe.js} +4 -9
- package/dist/chunks/{annotate-pSxJNPPL.js.map → annotate-NeITyYNe.js.map} +1 -1
- package/dist/chunks/{bootstrap-rINL2pCt.js → loader-DnJ3MHkt.js} +137 -127
- package/dist/chunks/loader-DnJ3MHkt.js.map +1 -0
- package/dist/chunks/{modal-Br-8TcEE.js → modal-C8Ca7E5j.js} +3 -3
- package/dist/chunks/{modal-Br-8TcEE.js.map → modal-C8Ca7E5j.js.map} +1 -1
- package/dist/chunks/{recording-BRvu1Vkh.js → recording-DhRZ6-tW.js} +133 -74
- package/dist/chunks/recording-DhRZ6-tW.js.map +1 -0
- package/dist/chunks/{targeting-_aii7qgw.js → targeting-BEQU2Ogo.js} +2 -2
- package/dist/chunks/{targeting-_aii7qgw.js.map → targeting-BEQU2Ogo.js.map} +1 -1
- package/dist/index.js +2569 -19
- package/dist/index.js.map +1 -1
- package/dist/loader.js +2 -4
- package/dist/loader.js.map +1 -1
- package/dist/qaid.umd.cjs +3 -3
- package/dist/qaid.umd.cjs.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/bootstrap-rINL2pCt.js.map +0 -1
- package/dist/chunks/network-capture-DMbMwwwR.js +0 -63
- package/dist/chunks/network-capture-DMbMwwwR.js.map +0 -1
- package/dist/chunks/recording-BRvu1Vkh.js.map +0 -1
|
@@ -1,19 +1,78 @@
|
|
|
1
|
-
import { b as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const e = u.createElement(d);
|
|
1
|
+
import { b as v } from "./annotate-NeITyYNe.js";
|
|
2
|
+
const g = document;
|
|
3
|
+
function r(n, t, ...o) {
|
|
4
|
+
const e = g.createElement(n);
|
|
6
5
|
if (t) {
|
|
7
6
|
if (t.class && (e.className = t.class), t.style && (e.style.cssText = t.style), t.html != null && (e.innerHTML = t.html), t.text != null && (e.textContent = t.text), t.attrs)
|
|
8
|
-
for (const
|
|
7
|
+
for (const i in t.attrs) e.setAttribute(i, t.attrs[i]);
|
|
9
8
|
if (t.on)
|
|
10
|
-
for (const
|
|
9
|
+
for (const i in t.on) e.addEventListener(i, t.on[i]);
|
|
11
10
|
}
|
|
12
|
-
for (const
|
|
13
|
-
|
|
11
|
+
for (const i of o)
|
|
12
|
+
i != null && i !== !1 && e.append(i);
|
|
14
13
|
return e;
|
|
15
14
|
}
|
|
16
|
-
|
|
15
|
+
const R = 20, u = 4096;
|
|
16
|
+
function l(n) {
|
|
17
|
+
const t = typeof n == "string" ? n : JSON.stringify(n);
|
|
18
|
+
return t.length > u ? t.slice(0, u) + "…[truncated]" : t;
|
|
19
|
+
}
|
|
20
|
+
function f(n, t) {
|
|
21
|
+
n.length >= R && n.shift(), n.push(t);
|
|
22
|
+
}
|
|
23
|
+
async function b(n) {
|
|
24
|
+
try {
|
|
25
|
+
const t = await n.clone().text();
|
|
26
|
+
return l(t);
|
|
27
|
+
} catch {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function y() {
|
|
32
|
+
const n = [], t = window.fetch;
|
|
33
|
+
window.fetch = async function(i, s) {
|
|
34
|
+
const d = typeof i == "string" ? i : i instanceof URL ? i.toString() : i.url, h = s?.method ?? (typeof i == "object" && "method" in i ? i.method : "GET");
|
|
35
|
+
let c;
|
|
36
|
+
s?.body && (c = l(s.body));
|
|
37
|
+
const a = await t.apply(window, [i, s]);
|
|
38
|
+
if (a.status >= 400) {
|
|
39
|
+
const p = await b(a);
|
|
40
|
+
f(n, {
|
|
41
|
+
url: d,
|
|
42
|
+
method: h.toUpperCase(),
|
|
43
|
+
status: a.status,
|
|
44
|
+
statusText: a.statusText,
|
|
45
|
+
requestBody: c,
|
|
46
|
+
responseBody: p,
|
|
47
|
+
timestamp: Date.now()
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return a;
|
|
51
|
+
};
|
|
52
|
+
const o = XMLHttpRequest.prototype.open, e = XMLHttpRequest.prototype.send;
|
|
53
|
+
return XMLHttpRequest.prototype.open = function(i, s, ...d) {
|
|
54
|
+
return this._qaid_method = i, this._qaid_url = typeof s == "string" ? s : s.toString(), o.apply(this, [i, s, ...d]);
|
|
55
|
+
}, XMLHttpRequest.prototype.send = function(i) {
|
|
56
|
+
const s = this, d = i ? l(i) : void 0;
|
|
57
|
+
return s.addEventListener("load", function() {
|
|
58
|
+
s.status >= 400 && f(n, {
|
|
59
|
+
url: s._qaid_url,
|
|
60
|
+
method: s._qaid_method.toUpperCase(),
|
|
61
|
+
status: s.status,
|
|
62
|
+
statusText: s.statusText,
|
|
63
|
+
requestBody: d,
|
|
64
|
+
responseBody: l(s.responseText),
|
|
65
|
+
timestamp: Date.now()
|
|
66
|
+
});
|
|
67
|
+
}), e.apply(this, [i]);
|
|
68
|
+
}, {
|
|
69
|
+
errors: n,
|
|
70
|
+
restore: () => {
|
|
71
|
+
window.fetch = t, XMLHttpRequest.prototype.open = o, XMLHttpRequest.prototype.send = e;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
class w {
|
|
17
76
|
constructor(t) {
|
|
18
77
|
this.host = t;
|
|
19
78
|
}
|
|
@@ -39,9 +98,9 @@ class g {
|
|
|
39
98
|
async startRecording(t = []) {
|
|
40
99
|
if (!(this.isRecording || this.host.state !== "IDLE"))
|
|
41
100
|
try {
|
|
42
|
-
this.networkCapture =
|
|
43
|
-
const { createVideoRecorder:
|
|
44
|
-
this.videoRecorder =
|
|
101
|
+
this.networkCapture = y();
|
|
102
|
+
const { createVideoRecorder: o } = await import("./video-BOYqf2Im.js");
|
|
103
|
+
this.videoRecorder = o({
|
|
45
104
|
maxDuration: this.host.config.videoOptions.maxDuration,
|
|
46
105
|
redactionElements: t
|
|
47
106
|
}), this.videoRecorder.onTick((e) => {
|
|
@@ -49,8 +108,8 @@ class g {
|
|
|
49
108
|
}), this.videoRecorder.onStop((e) => {
|
|
50
109
|
this.isRecording && (this.recordedBlob = e, this.isRecording = !1, this.host.announceMsg("Recording stopped"), this.removeRecordingIndicator(), document.removeEventListener("keydown", this.host.boundKeyDown), this.host.setButtonsDisabled(!1), e && e.size > 0 ? this.showRecordingPreview() : this.cleanupRecording());
|
|
51
110
|
}), await this.videoRecorder.start(), this.isRecording = !0, this.host.announceMsg("Recording started"), this.host.setButtonsDisabled(!0), this.showRecordingIndicator(), document.addEventListener("keydown", this.host.boundKeyDown);
|
|
52
|
-
} catch (
|
|
53
|
-
|
|
111
|
+
} catch (o) {
|
|
112
|
+
o instanceof Error && /current tab/i.test(o.message) && this.host.announceMsg(o.message), this.cleanupRecording();
|
|
54
113
|
}
|
|
55
114
|
}
|
|
56
115
|
async stopRecording() {
|
|
@@ -70,27 +129,27 @@ class g {
|
|
|
70
129
|
startPicking() {
|
|
71
130
|
if (this.isRecording || this.host.state !== "IDLE") return;
|
|
72
131
|
this.host.setState("REDACT_PICKING"), this.redactPicks = [];
|
|
73
|
-
const t = this.host.ensureOverlayHost(),
|
|
132
|
+
const t = this.host.ensureOverlayHost(), o = r("div", { style: "position:absolute;inset:0;" }), e = r(
|
|
74
133
|
"div",
|
|
75
134
|
{ class: "qaid-redact-picker", style: "position:fixed;inset:0;pointer-events:none;" },
|
|
76
|
-
|
|
135
|
+
o,
|
|
77
136
|
// Control bar — the only pointer-interactive part of the overlay.
|
|
78
|
-
|
|
137
|
+
r(
|
|
79
138
|
"div",
|
|
80
139
|
{
|
|
81
140
|
style: "position:fixed;left:50%;bottom:24px;transform:translateX(-50%);display:flex;gap:12px;align-items:center;pointer-events:auto;background:#0b1220;color:#fff;border:1px solid #ff6b6b;border-radius:9999px;padding:10px 16px;font:600 13px system-ui,sans-serif;box-shadow:0 8px 30px rgba(0,0,0,.5);"
|
|
82
141
|
},
|
|
83
|
-
|
|
142
|
+
r("span", {
|
|
84
143
|
text: "Click sensitive areas to blur",
|
|
85
144
|
attrs: { "data-qaid-redact-label": "" }
|
|
86
145
|
}),
|
|
87
|
-
|
|
146
|
+
r("button", {
|
|
88
147
|
text: "Start recording",
|
|
89
148
|
attrs: { type: "button" },
|
|
90
149
|
style: "cursor:pointer;border:0;border-radius:9999px;padding:8px 14px;background:#ff6b6b;color:#0b1220;font:inherit;",
|
|
91
150
|
on: { click: () => this.finishRedactionPicking(!0) }
|
|
92
151
|
}),
|
|
93
|
-
|
|
152
|
+
r("button", {
|
|
94
153
|
text: "Cancel",
|
|
95
154
|
attrs: { type: "button" },
|
|
96
155
|
style: "cursor:pointer;border:0;background:transparent;color:#9fb3c8;font:inherit;",
|
|
@@ -99,29 +158,29 @@ class g {
|
|
|
99
158
|
)
|
|
100
159
|
);
|
|
101
160
|
t.appendChild(e), this.redactPickerRoot = e;
|
|
102
|
-
const
|
|
103
|
-
this.renderRedactPicks(
|
|
161
|
+
const i = () => {
|
|
162
|
+
this.renderRedactPicks(o), this.redactRafId = requestAnimationFrame(i);
|
|
104
163
|
};
|
|
105
|
-
|
|
164
|
+
i(), document.addEventListener("click", this.boundRedactClick, !0), document.addEventListener("keydown", this.host.boundKeyDown), this.host.announceMsg("Click sensitive areas to blur, then start recording");
|
|
106
165
|
}
|
|
107
166
|
handleRedactPickClick(t) {
|
|
108
|
-
const
|
|
109
|
-
if (!
|
|
167
|
+
const o = t.target instanceof Element ? t.target : null;
|
|
168
|
+
if (!o || v(o) || this.redactPickerRoot?.contains(o)) return;
|
|
110
169
|
t.preventDefault(), t.stopPropagation();
|
|
111
|
-
const e = this.redactPicks.indexOf(
|
|
112
|
-
e >= 0 ? this.redactPicks.splice(e, 1) : this.redactPicks.push(
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
const
|
|
116
|
-
|
|
170
|
+
const e = this.redactPicks.indexOf(o);
|
|
171
|
+
e >= 0 ? this.redactPicks.splice(e, 1) : this.redactPicks.push(o);
|
|
172
|
+
const i = this.redactPickerRoot?.querySelector("[data-qaid-redact-label]");
|
|
173
|
+
if (i) {
|
|
174
|
+
const s = this.redactPicks.length;
|
|
175
|
+
i.textContent = s === 0 ? "Click sensitive areas to blur" : `${s} area${s === 1 ? "" : "s"} will be blurred`;
|
|
117
176
|
}
|
|
118
177
|
}
|
|
119
178
|
renderRedactPicks(t) {
|
|
120
179
|
t.textContent = "";
|
|
121
|
-
for (const
|
|
122
|
-
const e =
|
|
180
|
+
for (const o of this.redactPicks) {
|
|
181
|
+
const e = o.getBoundingClientRect();
|
|
123
182
|
e.width <= 0 || e.height <= 0 || t.appendChild(
|
|
124
|
-
|
|
183
|
+
r("div", {
|
|
125
184
|
style: `position:fixed;left:${e.left}px;top:${e.top}px;width:${e.width}px;height:${e.height}px;border:2px solid #ff6b6b;border-radius:4px;background:rgba(255,107,107,.18);pointer-events:none;`
|
|
126
185
|
})
|
|
127
186
|
);
|
|
@@ -129,20 +188,20 @@ class g {
|
|
|
129
188
|
}
|
|
130
189
|
finishRedactionPicking(t) {
|
|
131
190
|
this.redactRafId && cancelAnimationFrame(this.redactRafId), this.redactRafId = 0, document.removeEventListener("click", this.boundRedactClick, !0), document.removeEventListener("keydown", this.host.boundKeyDown), this.redactPickerRoot && (this.redactPickerRoot.remove(), this.redactPickerRoot = null);
|
|
132
|
-
const
|
|
133
|
-
this.redactPicks = [], this.host.setState("IDLE"), t && this.startRecording(
|
|
191
|
+
const o = this.redactPicks;
|
|
192
|
+
this.redactPicks = [], this.host.setState("IDLE"), t && this.startRecording(o);
|
|
134
193
|
}
|
|
135
194
|
showRecordingIndicator() {
|
|
136
195
|
const t = this.host.ensureOverlayHost();
|
|
137
|
-
this.recordingIndicator =
|
|
196
|
+
this.recordingIndicator = r(
|
|
138
197
|
"div",
|
|
139
198
|
{ class: "qaid-recording-indicator", style: `z-index:${this.host.config.zIndex + 100}` },
|
|
140
|
-
|
|
141
|
-
|
|
199
|
+
r("div", { class: "qaid-recording-dot" }),
|
|
200
|
+
r("span", {
|
|
142
201
|
class: "qaid-recording-time",
|
|
143
202
|
text: this.formatTime(this.host.config.videoOptions.maxDuration)
|
|
144
203
|
}),
|
|
145
|
-
|
|
204
|
+
r("button", {
|
|
146
205
|
class: "qaid-recording-stop",
|
|
147
206
|
text: "Stop",
|
|
148
207
|
attrs: { type: "button" },
|
|
@@ -152,48 +211,48 @@ class g {
|
|
|
152
211
|
}
|
|
153
212
|
updateRecordingTimer(t) {
|
|
154
213
|
if (!this.recordingIndicator) return;
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
214
|
+
const o = this.recordingIndicator.querySelector(".qaid-recording-time");
|
|
215
|
+
if (o) {
|
|
157
216
|
const e = Math.max(0, this.host.config.videoOptions.maxDuration - t);
|
|
158
|
-
|
|
217
|
+
o.textContent = this.formatTime(e), e > 0 && e <= 5 && this.host.announceMsg(`${e} second${e === 1 ? "" : "s"} remaining`);
|
|
159
218
|
}
|
|
160
219
|
}
|
|
161
220
|
formatTime(t) {
|
|
162
|
-
const
|
|
163
|
-
return `${
|
|
221
|
+
const o = Math.floor(t / 60), e = t % 60;
|
|
222
|
+
return `${o}:${e.toString().padStart(2, "0")}`;
|
|
164
223
|
}
|
|
165
224
|
removeRecordingIndicator() {
|
|
166
225
|
this.recordingIndicator && (this.recordingIndicator.remove(), this.recordingIndicator = null);
|
|
167
226
|
}
|
|
168
227
|
showRecordingPreview() {
|
|
169
|
-
const t = this.host.ensureOverlayHost(),
|
|
170
|
-
|
|
171
|
-
const
|
|
228
|
+
const t = this.host.ensureOverlayHost(), o = URL.createObjectURL(this.recordedBlob), e = `qaid-video-title-${this.host.uid}`, i = r("h3", { text: "Review your recording", attrs: { id: e } }), s = r("video");
|
|
229
|
+
s.src = o, s.controls = !0, s.autoplay = !0, s.muted = !0;
|
|
230
|
+
const d = r("textarea", {
|
|
172
231
|
attrs: {
|
|
173
232
|
placeholder: "Optional: Describe the issue you recorded...",
|
|
174
233
|
"aria-label": "Describe the issue you recorded"
|
|
175
234
|
}
|
|
176
|
-
}),
|
|
235
|
+
}), h = r("button", {
|
|
177
236
|
class: "qaid-video-btn qaid-video-btn-send",
|
|
178
237
|
text: "Send",
|
|
179
238
|
attrs: { type: "button" },
|
|
180
|
-
on: { click: () => this.submitVideoFeedback(
|
|
181
|
-
}),
|
|
239
|
+
on: { click: () => this.submitVideoFeedback(d.value.trim() || null, h) }
|
|
240
|
+
}), c = r(
|
|
182
241
|
"div",
|
|
183
242
|
{ class: "qaid-video-preview-box" },
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
243
|
+
i,
|
|
244
|
+
s,
|
|
245
|
+
d,
|
|
246
|
+
r(
|
|
188
247
|
"div",
|
|
189
248
|
{ class: "qaid-video-preview-actions" },
|
|
190
|
-
|
|
249
|
+
r("button", {
|
|
191
250
|
class: "qaid-video-btn qaid-video-btn-cancel",
|
|
192
251
|
text: "Cancel",
|
|
193
252
|
attrs: { type: "button" },
|
|
194
253
|
on: { click: () => this.cancelRecordingPreview() }
|
|
195
254
|
}),
|
|
196
|
-
|
|
255
|
+
r("button", {
|
|
197
256
|
class: "qaid-video-btn qaid-video-btn-rerecord",
|
|
198
257
|
text: "Re-record",
|
|
199
258
|
attrs: { type: "button" },
|
|
@@ -203,14 +262,14 @@ class g {
|
|
|
203
262
|
}
|
|
204
263
|
}
|
|
205
264
|
}),
|
|
206
|
-
|
|
265
|
+
h
|
|
207
266
|
)
|
|
208
267
|
);
|
|
209
|
-
this.videoPreview =
|
|
268
|
+
this.videoPreview = r(
|
|
210
269
|
"div",
|
|
211
270
|
{ class: "qaid-video-preview", style: `z-index:${this.host.config.zIndex + 100}` },
|
|
212
|
-
|
|
213
|
-
), this.host.applyVars(this.videoPreview), this.host.overlayShadowHost && (this.host.overlayShadowHost.style.pointerEvents = "auto"), t.appendChild(this.videoPreview), this.host.openDialogA11y(
|
|
271
|
+
c
|
|
272
|
+
), this.host.applyVars(this.videoPreview), this.host.overlayShadowHost && (this.host.overlayShadowHost.style.pointerEvents = "auto"), t.appendChild(this.videoPreview), this.host.openDialogA11y(c, { labelledbyId: i.id }), document.addEventListener("keydown", this.host.boundKeyDown);
|
|
214
273
|
}
|
|
215
274
|
cancelRecordingPreview() {
|
|
216
275
|
this.removeVideoPreview(), this.cleanupRecording();
|
|
@@ -222,35 +281,35 @@ class g {
|
|
|
222
281
|
}
|
|
223
282
|
document.removeEventListener("keydown", this.host.boundKeyDown);
|
|
224
283
|
}
|
|
225
|
-
async submitVideoFeedback(t,
|
|
284
|
+
async submitVideoFeedback(t, o) {
|
|
226
285
|
if (!this.recordedBlob || this.isSendingVideo) return;
|
|
227
|
-
this.isSendingVideo = !0,
|
|
286
|
+
this.isSendingVideo = !0, o.disabled = !0, o.textContent = "Sending...";
|
|
228
287
|
const e = new FormData();
|
|
229
288
|
e.append("video", this.recordedBlob, `recording.${this.recordedBlob.type.includes("mp4") ? "mp4" : "webm"}`), e.append("pageUrl", window.location.href), e.append("visitorId", this.host.visitorId), this.host.config.apiKey && e.append("apiKey", this.host.config.apiKey), t && e.append("message", t), this.host.consoleCapture && e.append("consoleErrors", JSON.stringify(this.host.consoleCapture.errors)), this.networkCapture && e.append("networkErrors", JSON.stringify(this.networkCapture.errors));
|
|
230
|
-
let
|
|
289
|
+
let i = null;
|
|
231
290
|
try {
|
|
232
|
-
const
|
|
291
|
+
const s = await fetch(`${this.host.config.endpoint}/video`, {
|
|
233
292
|
method: "POST",
|
|
234
293
|
body: e
|
|
235
294
|
});
|
|
236
|
-
if (
|
|
295
|
+
if (s.ok) {
|
|
237
296
|
this.host.announceMsg("Recording sent");
|
|
238
297
|
try {
|
|
239
|
-
|
|
298
|
+
i = (await s.json())?.id ?? null;
|
|
240
299
|
} catch {
|
|
241
300
|
}
|
|
242
301
|
} else
|
|
243
|
-
console.error("Failed to submit video feedback:", await
|
|
244
|
-
} catch (
|
|
245
|
-
console.error("Failed to submit video feedback:",
|
|
302
|
+
console.error("Failed to submit video feedback:", await s.text()), this.host.announceMsg("Failed to send recording", !0);
|
|
303
|
+
} catch (s) {
|
|
304
|
+
console.error("Failed to submit video feedback:", s), this.host.announceMsg("Failed to send recording", !0);
|
|
246
305
|
}
|
|
247
|
-
this.isSendingVideo = !1, this.removeVideoPreview(), this.cleanupRecording(), await this.host.tryLaunchQuest("video",
|
|
306
|
+
this.isSendingVideo = !1, this.removeVideoPreview(), this.cleanupRecording(), await this.host.tryLaunchQuest("video", i);
|
|
248
307
|
}
|
|
249
308
|
cleanupRecording() {
|
|
250
309
|
this.isRecording = !1, this.removeRecordingIndicator(), this.videoRecorder && (this.videoRecorder.destroy(), this.videoRecorder = null), this.networkCapture && (this.networkCapture.restore(), this.networkCapture = null), this.recordedBlob && (this.recordedBlob = null), this.host.setButtonsDisabled(!1), this.host.overlayShadowHost && this.host.state === "IDLE" && (this.host.overlayShadowHost.style.pointerEvents = "none");
|
|
251
310
|
}
|
|
252
311
|
}
|
|
253
312
|
export {
|
|
254
|
-
|
|
313
|
+
w as RecordingController
|
|
255
314
|
};
|
|
256
|
-
//# sourceMappingURL=recording-
|
|
315
|
+
//# sourceMappingURL=recording-DhRZ6-tW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recording-DhRZ6-tW.js","sources":["../../src/dom.ts","../../src/network-capture.ts","../../src/recording.ts"],"sourcesContent":["/**\n * Nano DOM factory — a purpose-built, construction-only helper for this embed.\n *\n * The embed builds all of its UI imperatively inside a Shadow DOM. That means\n * the same create → set class/style/attrs → wire events → append dance repeats\n * across every button, overlay, modal, and recording control. `h()` collapses\n * that dance into a single declarative expression.\n *\n * It is deliberately NOT a framework: no reactivity, no virtual DOM, no runtime\n * state. It only constructs. That fits what the embed actually needs (one-shot\n * DOM construction plus a few imperative updates), adds no dependency, and\n * keeps the package zero-dependency. Aliasing `document` here also lets the\n * minifier mangle the call site, which the global `document.createElement`\n * can't be.\n */\n\nconst d = document;\n\nexport interface ElProps {\n /** className */\n class?: string;\n /** Inline styles as a cssText string. */\n style?: string;\n /** innerHTML — for icons / trusted SVG markup. */\n html?: string;\n /** textContent. */\n text?: string;\n /** Attributes set via setAttribute (aria-*, data-*, type, role, …). */\n attrs?: Record<string, string>;\n /** Event listeners keyed by type. */\n on?: Record<string, (e: Event) => void>;\n}\n\ntype Child = Node | string | null | undefined | false;\n\n/**\n * Create an element, apply props, and append children. Falsy children are\n * skipped so conditional content reads cleanly (`cond && h(...)`).\n */\nexport function h<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n props?: ElProps | null,\n ...children: Child[]\n): HTMLElementTagNameMap[K] {\n const el = d.createElement(tag);\n if (props) {\n if (props.class) el.className = props.class;\n if (props.style) el.style.cssText = props.style;\n if (props.html != null) el.innerHTML = props.html;\n if (props.text != null) el.textContent = props.text;\n if (props.attrs) {\n for (const k in props.attrs) el.setAttribute(k, props.attrs[k]);\n }\n if (props.on) {\n for (const k in props.on) el.addEventListener(k, props.on[k]);\n }\n }\n for (const child of children) {\n if (child != null && child !== false) el.append(child);\n }\n return el;\n}\n","/**\n * Network capture utilities\n * Intercepts fetch() and XMLHttpRequest to capture 4xx/5xx errors\n */\n\nimport type { NetworkError } from \"./types\";\n\nconst MAX_ENTRIES = 20;\nconst MAX_BODY_SIZE = 4096; // 4KB\n\nexport interface NetworkCapture {\n errors: NetworkError[];\n restore: () => void;\n}\n\n/**\n * Truncate a body to max size. Callers must guard against null/undefined.\n */\nexport function truncateBody(body: unknown): string {\n const str = typeof body === \"string\" ? body : JSON.stringify(body);\n if (str.length > MAX_BODY_SIZE) {\n return str.slice(0, MAX_BODY_SIZE) + \"…[truncated]\";\n }\n return str;\n}\n\n/**\n * Add an error to the buffer, evicting oldest if at capacity\n */\nexport function addEntry(errors: NetworkError[], entry: NetworkError): void {\n if (errors.length >= MAX_ENTRIES) {\n errors.shift();\n }\n errors.push(entry);\n}\n\n/**\n * Read response body as text, with size limit\n */\nasync function safeReadBody(response: Response): Promise<string | undefined> {\n try {\n const text = await response.clone().text();\n return truncateBody(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Intercept fetch() and XMLHttpRequest to capture network errors (4xx/5xx)\n */\nexport function captureNetworkErrors(): NetworkCapture {\n const errors: NetworkError[] = [];\n const originalFetch = window.fetch;\n\n // Monkey-patch fetch\n window.fetch = async function (input: RequestInfo | URL, init?: RequestInit): Promise<Response> {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.toString() : input.url;\n const method = init?.method ?? (typeof input === \"object\" && \"method\" in input ? input.method : \"GET\");\n let requestBody: string | undefined;\n if (init?.body) {\n requestBody = truncateBody(init.body);\n }\n\n const response = await originalFetch.apply(window, [input, init]);\n\n if (response.status >= 400) {\n const responseBody = await safeReadBody(response);\n addEntry(errors, {\n url,\n method: method.toUpperCase(),\n status: response.status,\n statusText: response.statusText,\n requestBody,\n responseBody,\n timestamp: Date.now(),\n });\n }\n\n return response;\n };\n\n // Monkey-patch XMLHttpRequest\n const originalXHROpen = XMLHttpRequest.prototype.open;\n const originalXHRSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (method: string, url: string | URL, ...rest: unknown[]) {\n (this as XMLHttpRequest & { _qaid_method: string; _qaid_url: string })._qaid_method = method;\n (this as XMLHttpRequest & { _qaid_url: string })._qaid_url = typeof url === \"string\" ? url : url.toString();\n return originalXHROpen.apply(this, [method, url, ...rest] as Parameters<typeof originalXHROpen>);\n };\n\n XMLHttpRequest.prototype.send = function (body?: Document | XMLHttpRequestBodyInit | null) {\n const xhr = this as XMLHttpRequest & { _qaid_method: string; _qaid_url: string };\n const requestBody = body ? truncateBody(body) : undefined;\n\n xhr.addEventListener(\"load\", function () {\n if (xhr.status >= 400) {\n addEntry(errors, {\n url: xhr._qaid_url,\n method: xhr._qaid_method.toUpperCase(),\n status: xhr.status,\n statusText: xhr.statusText,\n requestBody,\n responseBody: truncateBody(xhr.responseText),\n timestamp: Date.now(),\n });\n }\n });\n\n return originalXHRSend.apply(this, [body]);\n };\n\n return {\n errors,\n restore: () => {\n window.fetch = originalFetch;\n XMLHttpRequest.prototype.open = originalXHROpen;\n XMLHttpRequest.prototype.send = originalXHRSend;\n },\n };\n}\n","/**\n * Video-recording subsystem — extracted from embed.ts so it lives in its own\n * lazily-loaded chunk. A thumbs-only visitor never downloads any of this; the\n * embed dynamically imports it the first time the record button is used (and\n * warms it on hover — see embed.ts prewarmVideo).\n *\n * The controller owns all recording state and UI (recorder, redaction picker,\n * indicator, preview, submit). It talks back to the embed through the narrow\n * `RecordingHost` interface, so embed internals stay private and the coupling\n * is explicit.\n */\n\nimport { h } from \"./dom\";\nimport { isEmbedElement } from \"./dom-utils\";\nimport { captureNetworkErrors, type NetworkCapture } from \"./network-capture\";\nimport type { VideoRecorder } from \"./video-capture\";\nimport type { ResolvedFeedbackConfig, EmbedState } from \"./types\";\nimport type { ConsoleCapture } from \"./console-capture\";\n\n/** The slice of the embed the recording subsystem needs. */\nexport interface RecordingHost {\n readonly config: ResolvedFeedbackConfig;\n readonly visitorId: string;\n readonly uid: string;\n readonly overlayShadowHost: HTMLDivElement | null;\n readonly consoleCapture: ConsoleCapture | null;\n readonly boundKeyDown: (e: KeyboardEvent) => void;\n readonly state: EmbedState;\n setState(state: EmbedState): void;\n ensureOverlayHost(): ShadowRoot;\n applyVars(el: HTMLElement): void;\n announceMsg(message: string, assertive?: boolean): void;\n openDialogA11y(\n container: HTMLElement,\n opts: { labelledbyId?: string; describedbyId?: string; label?: string }\n ): void;\n closeDialogA11y(): void;\n setButtonsDisabled(disabled: boolean): void;\n tryLaunchQuest(\n type: \"up\" | \"down\" | \"video\",\n feedbackId: number | string | null\n ): Promise<boolean>;\n}\n\nexport class RecordingController {\n private videoRecorder: VideoRecorder | null = null;\n private networkCapture: NetworkCapture | null = null;\n private recordedBlob: Blob | null = null;\n private recordingIndicator: HTMLDivElement | null = null;\n private videoPreview: HTMLDivElement | null = null;\n private isRecording = false;\n private isSendingVideo = false;\n\n // Pre-recording redaction picking.\n private redactPicks: Element[] = [];\n private redactPickerRoot: HTMLDivElement | null = null;\n private redactRafId = 0;\n private boundRedactClick = (e: MouseEvent): void => this.handleRedactPickClick(e);\n\n constructor(private host: RecordingHost) {}\n\n /** Escape-key handler; returns true when it consumed the key. */\n handleEscape(): boolean {\n if (this.isRecording) {\n void this.stopRecording();\n return true;\n }\n if (this.videoPreview) {\n this.cancelRecordingPreview();\n return true;\n }\n if (this.redactPickerRoot) {\n this.finishRedactionPicking(false);\n return true;\n }\n return false;\n }\n\n destroy(): void {\n if (this.redactRafId) cancelAnimationFrame(this.redactRafId);\n this.redactRafId = 0;\n document.removeEventListener(\"click\", this.boundRedactClick, true);\n if (this.redactPickerRoot) {\n this.redactPickerRoot.remove();\n this.redactPickerRoot = null;\n }\n this.redactPicks = [];\n this.cleanupRecording();\n this.removeVideoPreview();\n }\n\n async startRecording(redactionElements: Element[] = []): Promise<void> {\n // Don't start if already recording or in a targeting/modal flow.\n if (this.isRecording || this.host.state !== \"IDLE\") return;\n\n try {\n this.networkCapture = captureNetworkErrors();\n\n const { createVideoRecorder } = await import(\"./video-capture\");\n this.videoRecorder = createVideoRecorder({\n maxDuration: this.host.config.videoOptions.maxDuration,\n redactionElements,\n });\n\n this.videoRecorder.onTick((elapsed) => {\n this.updateRecordingTimer(elapsed);\n });\n\n // Handle unexpected stops (browser stop button, max duration).\n this.videoRecorder.onStop((blob) => {\n if (this.isRecording) {\n this.recordedBlob = blob;\n this.isRecording = false;\n this.host.announceMsg(\"Recording stopped\");\n this.removeRecordingIndicator();\n document.removeEventListener(\"keydown\", this.host.boundKeyDown);\n this.host.setButtonsDisabled(false);\n\n if (blob && blob.size > 0) {\n this.showRecordingPreview();\n } else {\n this.cleanupRecording();\n }\n }\n });\n\n await this.videoRecorder.start();\n this.isRecording = true;\n this.host.announceMsg(\"Recording started\");\n this.host.setButtonsDisabled(true);\n this.showRecordingIndicator();\n document.addEventListener(\"keydown\", this.host.boundKeyDown);\n } catch (error) {\n // User denied screen share, shared a disallowed surface (window / whole\n // screen), or another error occurred. Surface the tab-only message so a\n // rejected non-tab share isn't a silent no-op.\n if (error instanceof Error && /current tab/i.test(error.message)) {\n this.host.announceMsg(error.message);\n }\n this.cleanupRecording();\n }\n }\n\n private async stopRecording(): Promise<void> {\n try {\n this.recordedBlob = await this.videoRecorder!.stop();\n } catch {\n this.recordedBlob = null;\n }\n\n this.isRecording = false;\n this.host.announceMsg(\"Recording stopped\");\n this.removeRecordingIndicator();\n document.removeEventListener(\"keydown\", this.host.boundKeyDown);\n\n if (this.recordedBlob && this.recordedBlob.size > 0) {\n this.showRecordingPreview();\n } else {\n this.cleanupRecording();\n }\n }\n\n /**\n * Pre-recording redaction picker. The user clicks page areas to blur; each\n * gets an outline that tracks its position, then \"Start recording\" hands the\n * picks to the recorder, which blurs their live bounding boxes so the\n * redaction follows the content as the page scrolls. \"Cancel\"/Escape aborts.\n */\n startPicking(): void {\n if (this.isRecording || this.host.state !== \"IDLE\") return;\n this.host.setState(\"REDACT_PICKING\");\n this.redactPicks = [];\n\n const root = this.host.ensureOverlayHost();\n\n // Layer holding the per-pick outlines (repositioned every frame).\n const boxHost = h(\"div\", { style: \"position:absolute;inset:0;\" });\n\n const container = h(\n \"div\",\n { class: \"qaid-redact-picker\", style: \"position:fixed;inset:0;pointer-events:none;\" },\n boxHost,\n // Control bar — the only pointer-interactive part of the overlay.\n h(\n \"div\",\n {\n style:\n \"position:fixed;left:50%;bottom:24px;transform:translateX(-50%);\" +\n \"display:flex;gap:12px;align-items:center;pointer-events:auto;\" +\n \"background:#0b1220;color:#fff;border:1px solid #ff6b6b;border-radius:9999px;\" +\n \"padding:10px 16px;font:600 13px system-ui,sans-serif;box-shadow:0 8px 30px rgba(0,0,0,.5);\",\n },\n h(\"span\", {\n text: \"Click sensitive areas to blur\",\n attrs: { \"data-qaid-redact-label\": \"\" },\n }),\n h(\"button\", {\n text: \"Start recording\",\n attrs: { type: \"button\" },\n style:\n \"cursor:pointer;border:0;border-radius:9999px;padding:8px 14px;background:#ff6b6b;color:#0b1220;font:inherit;\",\n on: { click: () => this.finishRedactionPicking(true) },\n }),\n h(\"button\", {\n text: \"Cancel\",\n attrs: { type: \"button\" },\n style: \"cursor:pointer;border:0;background:transparent;color:#9fb3c8;font:inherit;\",\n on: { click: () => this.finishRedactionPicking(false) },\n }),\n ),\n );\n\n root.appendChild(container);\n this.redactPickerRoot = container;\n\n // Keep the outlines glued to their elements while the user scrolls/picks.\n const tick = (): void => {\n this.renderRedactPicks(boxHost);\n this.redactRafId = requestAnimationFrame(tick);\n };\n tick();\n\n document.addEventListener(\"click\", this.boundRedactClick, true);\n document.addEventListener(\"keydown\", this.host.boundKeyDown);\n this.host.announceMsg(\"Click sensitive areas to blur, then start recording\");\n }\n\n private handleRedactPickClick(e: MouseEvent): void {\n const target = e.target instanceof Element ? e.target : null;\n // Ignore clicks on the embed's own UI. isEmbedElement catches the retargeted\n // shadow host (real browsers compose click events to it); the contains()\n // check catches the picker's own control-bar buttons when the event isn't\n // retargeted, so their handlers still fire instead of being swallowed here.\n if (!target || isEmbedElement(target) || this.redactPickerRoot?.contains(target)) return;\n e.preventDefault();\n e.stopPropagation();\n\n const idx = this.redactPicks.indexOf(target);\n if (idx >= 0) {\n this.redactPicks.splice(idx, 1);\n } else {\n this.redactPicks.push(target);\n }\n\n const label = this.redactPickerRoot?.querySelector(\"[data-qaid-redact-label]\");\n if (label) {\n const n = this.redactPicks.length;\n label.textContent =\n n === 0 ? \"Click sensitive areas to blur\" : `${n} area${n === 1 ? \"\" : \"s\"} will be blurred`;\n }\n }\n\n private renderRedactPicks(layer: HTMLElement): void {\n // Rebuild the outline boxes to match current picks and their live positions.\n layer.textContent = \"\";\n for (const el of this.redactPicks) {\n const r = el.getBoundingClientRect();\n if (r.width <= 0 || r.height <= 0) continue;\n layer.appendChild(\n h(\"div\", {\n style:\n `position:fixed;left:${r.left}px;top:${r.top}px;width:${r.width}px;height:${r.height}px;` +\n \"border:2px solid #ff6b6b;border-radius:4px;background:rgba(255,107,107,.18);pointer-events:none;\",\n }),\n );\n }\n }\n\n private finishRedactionPicking(record: boolean): void {\n if (this.redactRafId) cancelAnimationFrame(this.redactRafId);\n this.redactRafId = 0;\n document.removeEventListener(\"click\", this.boundRedactClick, true);\n document.removeEventListener(\"keydown\", this.host.boundKeyDown);\n if (this.redactPickerRoot) {\n this.redactPickerRoot.remove();\n this.redactPickerRoot = null;\n }\n const picks = this.redactPicks;\n this.redactPicks = [];\n this.host.setState(\"IDLE\");\n if (record) {\n void this.startRecording(picks);\n }\n }\n\n private showRecordingIndicator(): void {\n const root = this.host.ensureOverlayHost();\n\n this.recordingIndicator = h(\n \"div\",\n { class: \"qaid-recording-indicator\", style: `z-index:${this.host.config.zIndex + 100}` },\n h(\"div\", { class: \"qaid-recording-dot\" }),\n h(\"span\", {\n class: \"qaid-recording-time\",\n text: this.formatTime(this.host.config.videoOptions.maxDuration),\n }),\n h(\"button\", {\n class: \"qaid-recording-stop\",\n text: \"Stop\",\n attrs: { type: \"button\" },\n on: { click: () => this.stopRecording() },\n }),\n );\n\n this.host.applyVars(this.recordingIndicator);\n\n // Enable pointer events on the overlay host for the recording indicator.\n if (this.host.overlayShadowHost) {\n this.host.overlayShadowHost.style.pointerEvents = \"auto\";\n }\n\n root.appendChild(this.recordingIndicator);\n }\n\n private updateRecordingTimer(elapsed: number): void {\n if (!this.recordingIndicator) return;\n const timer = this.recordingIndicator.querySelector<HTMLSpanElement>(\".qaid-recording-time\");\n if (timer) {\n const remaining = Math.max(0, this.host.config.videoOptions.maxDuration - elapsed);\n timer.textContent = this.formatTime(remaining);\n // Announce the final countdown so it is perceivable non-visually.\n if (remaining > 0 && remaining <= 5) {\n this.host.announceMsg(`${remaining} second${remaining === 1 ? \"\" : \"s\"} remaining`);\n }\n }\n }\n\n private formatTime(seconds: number): string {\n const m = Math.floor(seconds / 60);\n const s = seconds % 60;\n return `${m}:${s.toString().padStart(2, \"0\")}`;\n }\n\n private removeRecordingIndicator(): void {\n if (this.recordingIndicator) {\n this.recordingIndicator.remove();\n this.recordingIndicator = null;\n }\n }\n\n private showRecordingPreview(): void {\n const root = this.host.ensureOverlayHost();\n\n const videoUrl = URL.createObjectURL(this.recordedBlob!);\n const titleId = `qaid-video-title-${this.host.uid}`;\n\n const title = h(\"h3\", { text: \"Review your recording\", attrs: { id: titleId } });\n\n // Boolean media props must be set as properties (the `muted` attribute is\n // unreliable for autoplay), so build the element then assign them.\n const videoEl = h(\"video\");\n videoEl.src = videoUrl;\n videoEl.controls = true;\n videoEl.autoplay = true;\n videoEl.muted = true;\n\n const textarea = h(\"textarea\", {\n attrs: {\n placeholder: \"Optional: Describe the issue you recorded...\",\n \"aria-label\": \"Describe the issue you recorded\",\n },\n });\n\n const sendBtn = h(\"button\", {\n class: \"qaid-video-btn qaid-video-btn-send\",\n text: \"Send\",\n attrs: { type: \"button\" },\n on: { click: () => this.submitVideoFeedback(textarea.value.trim() || null, sendBtn) },\n });\n\n const box = h(\n \"div\",\n { class: \"qaid-video-preview-box\" },\n title,\n videoEl,\n textarea,\n h(\n \"div\",\n { class: \"qaid-video-preview-actions\" },\n h(\"button\", {\n class: \"qaid-video-btn qaid-video-btn-cancel\",\n text: \"Cancel\",\n attrs: { type: \"button\" },\n on: { click: () => this.cancelRecordingPreview() },\n }),\n h(\"button\", {\n class: \"qaid-video-btn qaid-video-btn-rerecord\",\n text: \"Re-record\",\n attrs: { type: \"button\" },\n on: {\n click: () => {\n this.cancelRecordingPreview();\n this.startRecording();\n },\n },\n }),\n sendBtn,\n ),\n );\n\n this.videoPreview = h(\n \"div\",\n { class: \"qaid-video-preview\", style: `z-index:${this.host.config.zIndex + 100}` },\n box,\n );\n\n this.host.applyVars(this.videoPreview);\n\n // Enable pointer events on the overlay host for the video preview.\n if (this.host.overlayShadowHost) {\n this.host.overlayShadowHost.style.pointerEvents = \"auto\";\n }\n\n root.appendChild(this.videoPreview);\n\n // Dialog semantics + focus trap + background inert.\n this.host.openDialogA11y(box, { labelledbyId: title.id });\n\n // Listen for the escape key.\n document.addEventListener(\"keydown\", this.host.boundKeyDown);\n }\n\n private cancelRecordingPreview(): void {\n this.removeVideoPreview();\n this.cleanupRecording();\n }\n\n private removeVideoPreview(): void {\n // Release focus trap / inert and restore focus before removing the DOM.\n this.host.closeDialogA11y();\n if (this.videoPreview) {\n const videoEl = this.videoPreview.querySelector<HTMLVideoElement>(\"video\");\n if (videoEl?.src) {\n URL.revokeObjectURL(videoEl.src);\n }\n this.videoPreview.remove();\n this.videoPreview = null;\n }\n document.removeEventListener(\"keydown\", this.host.boundKeyDown);\n }\n\n private async submitVideoFeedback(message: string | null, sendBtn: HTMLButtonElement): Promise<void> {\n if (!this.recordedBlob || this.isSendingVideo) return;\n\n this.isSendingVideo = true;\n sendBtn.disabled = true;\n sendBtn.textContent = \"Sending...\";\n\n const formData = new FormData();\n formData.append(\"video\", this.recordedBlob, `recording.${this.recordedBlob.type.includes(\"mp4\") ? \"mp4\" : \"webm\"}`);\n formData.append(\"pageUrl\", window.location.href);\n formData.append(\"visitorId\", this.host.visitorId);\n\n if (this.host.config.apiKey) {\n formData.append(\"apiKey\", this.host.config.apiKey);\n }\n if (message) {\n formData.append(\"message\", message);\n }\n if (this.host.consoleCapture) {\n formData.append(\"consoleErrors\", JSON.stringify(this.host.consoleCapture.errors));\n }\n if (this.networkCapture) {\n formData.append(\"networkErrors\", JSON.stringify(this.networkCapture.errors));\n }\n\n let videoFeedbackId: string | number | null = null;\n try {\n const response = await fetch(`${this.host.config.endpoint}/video`, {\n method: \"POST\",\n body: formData,\n });\n\n if (response.ok) {\n this.host.announceMsg(\"Recording sent\");\n try {\n const data = (await response.json()) as { id?: string | number };\n videoFeedbackId = data?.id ?? null;\n } catch {\n // Non-JSON / no id — the quest can still launch, just unlinked.\n }\n } else {\n console.error(\"Failed to submit video feedback:\", await response.text());\n this.host.announceMsg(\"Failed to send recording\", true);\n }\n } catch (error) {\n console.error(\"Failed to submit video feedback:\", error);\n this.host.announceMsg(\"Failed to send recording\", true);\n }\n\n this.isSendingVideo = false;\n this.removeVideoPreview();\n this.cleanupRecording();\n\n // Once the recording is safely sent, launch the linked quest (if any),\n // passing the new feedback record id so its response is joinable.\n await this.host.tryLaunchQuest(\"video\", videoFeedbackId);\n }\n\n private cleanupRecording(): void {\n this.isRecording = false;\n this.removeRecordingIndicator();\n\n if (this.videoRecorder) {\n this.videoRecorder.destroy();\n this.videoRecorder = null;\n }\n if (this.networkCapture) {\n this.networkCapture.restore();\n this.networkCapture = null;\n }\n if (this.recordedBlob) {\n this.recordedBlob = null;\n }\n\n this.host.setButtonsDisabled(false);\n\n // Reset overlay host pointer events if nothing else needs them.\n if (this.host.overlayShadowHost && this.host.state === \"IDLE\") {\n this.host.overlayShadowHost.style.pointerEvents = \"none\";\n }\n }\n}\n"],"names":["d","h","tag","props","children","el","k","child","MAX_ENTRIES","MAX_BODY_SIZE","truncateBody","body","str","addEntry","errors","entry","safeReadBody","response","text","captureNetworkErrors","originalFetch","input","init","url","method","requestBody","responseBody","originalXHROpen","originalXHRSend","rest","xhr","RecordingController","host","e","redactionElements","createVideoRecorder","elapsed","blob","error","root","boxHost","container","tick","target","isEmbedElement","idx","label","n","layer","r","record","picks","timer","remaining","seconds","m","s","videoUrl","titleId","title","videoEl","textarea","sendBtn","box","message","formData","videoFeedbackId"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as k,
|
|
1
|
+
import { g as k, c as T, b as m } from "./annotate-NeITyYNe.js";
|
|
2
2
|
const E = ["data-comp", "data-qa", "data-testid", "data-id"];
|
|
3
3
|
function C(s, t = document.body) {
|
|
4
4
|
let e = s;
|
|
@@ -292,4 +292,4 @@ class O {
|
|
|
292
292
|
export {
|
|
293
293
|
O as TargetingController
|
|
294
294
|
};
|
|
295
|
-
//# sourceMappingURL=targeting-
|
|
295
|
+
//# sourceMappingURL=targeting-BEQU2Ogo.js.map
|