glitchgrab 1.40.0 → 1.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +262 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +262 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -832,7 +832,7 @@ response.headers.set(
|
|
|
832
832
|
|
|
833
833
|
- `connect-src https://glitchgrab.dev` — required for `sendReport`, `enhanceText`, `transcribeAudio`, and the report-fetching hooks/REST calls. All SDK requests go to this single host by default.
|
|
834
834
|
- If you pass a custom `baseUrl` prop, allow that host instead (self-hosted or proxied deployments).
|
|
835
|
-
- Screenshot capture
|
|
835
|
+
- Screenshot capture runs entirely client-side — no network request, no extra `img-src`/`connect-src` needed for it. In Chrome and Edge the browser asks "Allow this site to see this tab?" when the dialog opens, and the screenshot is the tab's real pixels (the share stops after one frame). If the reporter clicks Cancel, or in Safari/Firefox, it falls back to re-drawing `document.body` with `html2canvas-pro`, which needs no permission but can drift from the real UI. If the SDK runs inside an iframe, the frame needs `allow="display-capture"` for the real-pixel path.
|
|
836
836
|
- `img-src` only matters if your `session` carries an avatar URL — the report dialog renders it. If your CSP blocks that host the dialog falls back to the reporter's initials, so it degrades rather than breaking.
|
|
837
837
|
- No `script-src`, `style-src`, or `frame-src` allowances are required — the SDK doesn't load remote scripts, styles, or iframes.
|
|
838
838
|
|
package/dist/index.js
CHANGED
|
@@ -1314,6 +1314,7 @@ function AssistSheet({
|
|
|
1314
1314
|
assist,
|
|
1315
1315
|
theme: t2,
|
|
1316
1316
|
screenshots,
|
|
1317
|
+
pageShot = null,
|
|
1317
1318
|
onAddImages,
|
|
1318
1319
|
attachmentCount,
|
|
1319
1320
|
context,
|
|
@@ -1359,6 +1360,34 @@ function AssistSheet({
|
|
|
1359
1360
|
const inputRef = (0, import_react3.useRef)(null);
|
|
1360
1361
|
const draftRef = (0, import_react3.useRef)(null);
|
|
1361
1362
|
const seededRef = (0, import_react3.useRef)(false);
|
|
1363
|
+
const eventsRef = (0, import_react3.useRef)([]);
|
|
1364
|
+
const aiDraftRef = (0, import_react3.useRef)(null);
|
|
1365
|
+
function logEvent(type, detail) {
|
|
1366
|
+
eventsRef.current.push({ type, at: Date.now(), ...detail ? { detail } : {} });
|
|
1367
|
+
}
|
|
1368
|
+
function takeEvents() {
|
|
1369
|
+
if (eventsRef.current.length === 0) return void 0;
|
|
1370
|
+
const events = eventsRef.current;
|
|
1371
|
+
eventsRef.current = [];
|
|
1372
|
+
return events;
|
|
1373
|
+
}
|
|
1374
|
+
function flushEvents() {
|
|
1375
|
+
if (!conversationId) return;
|
|
1376
|
+
const events = takeEvents();
|
|
1377
|
+
if (!events) return;
|
|
1378
|
+
try {
|
|
1379
|
+
void Promise.resolve(
|
|
1380
|
+
assist({ messages: [], conversationId, events, screenshots: [], context: null })
|
|
1381
|
+
).catch(() => {
|
|
1382
|
+
});
|
|
1383
|
+
} catch (e) {
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
function leave(type, detail) {
|
|
1387
|
+
logEvent(type, detail);
|
|
1388
|
+
flushEvents();
|
|
1389
|
+
onClose();
|
|
1390
|
+
}
|
|
1362
1391
|
(0, import_react3.useEffect)(() => {
|
|
1363
1392
|
const el = scrollRef.current;
|
|
1364
1393
|
if (el) el.scrollTop = el.scrollHeight;
|
|
@@ -1367,27 +1396,45 @@ function AssistSheet({
|
|
|
1367
1396
|
var _a;
|
|
1368
1397
|
if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
|
|
1369
1398
|
}, [phase]);
|
|
1399
|
+
function degradeKeepingEvents(events, message) {
|
|
1400
|
+
if (events) eventsRef.current = [...events, ...eventsRef.current];
|
|
1401
|
+
flushEvents();
|
|
1402
|
+
onDegrade(message);
|
|
1403
|
+
}
|
|
1370
1404
|
async function runTurn(history2) {
|
|
1371
1405
|
var _a, _b, _c, _d, _e;
|
|
1372
1406
|
setBusy(true);
|
|
1373
1407
|
let result;
|
|
1408
|
+
const events = takeEvents();
|
|
1374
1409
|
try {
|
|
1375
1410
|
const sent = screenshots.slice(-MAX_ASSIST_IMAGES);
|
|
1376
1411
|
result = await assist({
|
|
1377
|
-
|
|
1412
|
+
// `kind` only on drafts, so an older server sees the exact shape it
|
|
1413
|
+
// always did — it just learns the draft text now instead of a
|
|
1414
|
+
// placeholder line.
|
|
1415
|
+
messages: history2.map(
|
|
1416
|
+
(m) => m.kind ? { role: m.role, content: m.content, kind: m.kind } : m
|
|
1417
|
+
),
|
|
1378
1418
|
conversationId,
|
|
1379
1419
|
screenshots: sent,
|
|
1380
1420
|
screenshot: (_a = sent[sent.length - 1]) != null ? _a : null,
|
|
1381
|
-
context
|
|
1421
|
+
context: {
|
|
1422
|
+
...context != null ? context : {},
|
|
1423
|
+
imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached")
|
|
1424
|
+
},
|
|
1425
|
+
events
|
|
1382
1426
|
});
|
|
1383
1427
|
} catch (e) {
|
|
1384
|
-
|
|
1428
|
+
degradeKeepingEvents(
|
|
1429
|
+
events,
|
|
1430
|
+
"The assistant is unavailable \u2014 write your report below and send it as normal."
|
|
1431
|
+
);
|
|
1385
1432
|
return;
|
|
1386
1433
|
} finally {
|
|
1387
1434
|
setBusy(false);
|
|
1388
1435
|
}
|
|
1389
1436
|
if (result.degraded) {
|
|
1390
|
-
|
|
1437
|
+
degradeKeepingEvents(events, result.degraded);
|
|
1391
1438
|
return;
|
|
1392
1439
|
}
|
|
1393
1440
|
if (result.conversationId) {
|
|
@@ -1404,7 +1451,9 @@ function AssistSheet({
|
|
|
1404
1451
|
}
|
|
1405
1452
|
if (result.report) {
|
|
1406
1453
|
onDescriptionChange(result.report);
|
|
1407
|
-
|
|
1454
|
+
aiDraftRef.current = result.report;
|
|
1455
|
+
logEvent("draft_shown");
|
|
1456
|
+
setMessages([...history2, { role: "assistant", content: result.report, kind: "report" }]);
|
|
1408
1457
|
setOptions([]);
|
|
1409
1458
|
setPhase("draft");
|
|
1410
1459
|
return;
|
|
@@ -1439,6 +1488,36 @@ function AssistSheet({
|
|
|
1439
1488
|
onPickType(tile);
|
|
1440
1489
|
setPhase(tile === "RATING" ? "rating" : "chat");
|
|
1441
1490
|
}
|
|
1491
|
+
function keepChatting() {
|
|
1492
|
+
const current = description.trim();
|
|
1493
|
+
logEvent(
|
|
1494
|
+
"keep_chatting",
|
|
1495
|
+
aiDraftRef.current && current !== aiDraftRef.current.trim() ? "after editing" : void 0
|
|
1496
|
+
);
|
|
1497
|
+
setMessages((prev) => {
|
|
1498
|
+
const next = [...prev];
|
|
1499
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
1500
|
+
if (next[i].kind === "report") {
|
|
1501
|
+
if (current) next[i] = { ...next[i], content: current };
|
|
1502
|
+
break;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
return next;
|
|
1506
|
+
});
|
|
1507
|
+
setPhase("chat");
|
|
1508
|
+
requestAnimationFrame(() => {
|
|
1509
|
+
var _a;
|
|
1510
|
+
return (_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
function sendDraft() {
|
|
1514
|
+
const edited = aiDraftRef.current !== null && description.trim() !== aiDraftRef.current.trim();
|
|
1515
|
+
logEvent("draft_sent", edited ? "edited" : "as drafted");
|
|
1516
|
+
flushEvents();
|
|
1517
|
+
onSend();
|
|
1518
|
+
}
|
|
1519
|
+
const lastMessage = messages[messages.length - 1];
|
|
1520
|
+
const correcting = phase === "chat" && (lastMessage == null ? void 0 : lastMessage.kind) === "report";
|
|
1442
1521
|
const empty = phase === "chat" && messages.length === 0 && !busy;
|
|
1443
1522
|
const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
|
|
1444
1523
|
var _a, _b;
|
|
@@ -1484,7 +1563,7 @@ function AssistSheet({
|
|
|
1484
1563
|
animation: "gg-sheet-fade .18s ease",
|
|
1485
1564
|
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
1486
1565
|
},
|
|
1487
|
-
onClick:
|
|
1566
|
+
onClick: () => leave("closed"),
|
|
1488
1567
|
onPointerDown: (e) => e.stopPropagation(),
|
|
1489
1568
|
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1490
1569
|
"div",
|
|
@@ -1564,7 +1643,7 @@ function AssistSheet({
|
|
|
1564
1643
|
{
|
|
1565
1644
|
type: "button",
|
|
1566
1645
|
"data-gg-write-myself": "",
|
|
1567
|
-
onClick:
|
|
1646
|
+
onClick: () => leave("write_myself", `header, ${phase}`),
|
|
1568
1647
|
"aria-label": "Write it myself instead",
|
|
1569
1648
|
style: {
|
|
1570
1649
|
flexShrink: 0,
|
|
@@ -1820,7 +1899,10 @@ function AssistSheet({
|
|
|
1820
1899
|
{
|
|
1821
1900
|
type: "button",
|
|
1822
1901
|
"data-gg-chip": "",
|
|
1823
|
-
onClick: () =>
|
|
1902
|
+
onClick: () => {
|
|
1903
|
+
logEvent("starter_tap", s);
|
|
1904
|
+
send(s);
|
|
1905
|
+
},
|
|
1824
1906
|
style: {
|
|
1825
1907
|
border: `1px solid ${t2.inputBorder}`,
|
|
1826
1908
|
background: "transparent",
|
|
@@ -1840,6 +1922,60 @@ function AssistSheet({
|
|
|
1840
1922
|
] }),
|
|
1841
1923
|
messages.map((m, i) => {
|
|
1842
1924
|
const mine = m.role === "user";
|
|
1925
|
+
if (m.kind === "report") {
|
|
1926
|
+
const live = phase === "draft" && i === messages.length - 1;
|
|
1927
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", minWidth: 0 }, children: [
|
|
1928
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { who: "assistant", theme: t2 }),
|
|
1929
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1930
|
+
"div",
|
|
1931
|
+
{
|
|
1932
|
+
"data-gg-draft-bubble": "",
|
|
1933
|
+
style: {
|
|
1934
|
+
maxWidth: "82%",
|
|
1935
|
+
minWidth: 0,
|
|
1936
|
+
padding: "9px 12px",
|
|
1937
|
+
borderRadius: "12px 12px 12px 4px",
|
|
1938
|
+
fontSize: "13px",
|
|
1939
|
+
lineHeight: 1.55,
|
|
1940
|
+
backgroundColor: t2.bgSecondary,
|
|
1941
|
+
color: t2.text,
|
|
1942
|
+
border: live ? "none" : `1px solid ${t2.accent}66`
|
|
1943
|
+
},
|
|
1944
|
+
children: live ? "Here's your report \u2014 have a read." : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
1945
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1946
|
+
"span",
|
|
1947
|
+
{
|
|
1948
|
+
style: {
|
|
1949
|
+
display: "block",
|
|
1950
|
+
fontSize: "10px",
|
|
1951
|
+
fontWeight: 700,
|
|
1952
|
+
letterSpacing: ".06em",
|
|
1953
|
+
textTransform: "uppercase",
|
|
1954
|
+
color: t2.accent,
|
|
1955
|
+
marginBottom: "4px"
|
|
1956
|
+
},
|
|
1957
|
+
children: "Draft so far"
|
|
1958
|
+
}
|
|
1959
|
+
),
|
|
1960
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1961
|
+
"span",
|
|
1962
|
+
{
|
|
1963
|
+
style: {
|
|
1964
|
+
display: "block",
|
|
1965
|
+
whiteSpace: "pre-wrap",
|
|
1966
|
+
wordBreak: "break-word",
|
|
1967
|
+
maxHeight: "160px",
|
|
1968
|
+
overflowY: "auto",
|
|
1969
|
+
color: t2.textMuted
|
|
1970
|
+
},
|
|
1971
|
+
children: m.content
|
|
1972
|
+
}
|
|
1973
|
+
)
|
|
1974
|
+
] })
|
|
1975
|
+
}
|
|
1976
|
+
)
|
|
1977
|
+
] }, i);
|
|
1978
|
+
}
|
|
1843
1979
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1844
1980
|
"div",
|
|
1845
1981
|
{
|
|
@@ -1894,7 +2030,10 @@ function AssistSheet({
|
|
|
1894
2030
|
type: "button",
|
|
1895
2031
|
"data-gg-chip": "",
|
|
1896
2032
|
"data-gg-option": "",
|
|
1897
|
-
onClick: () =>
|
|
2033
|
+
onClick: () => {
|
|
2034
|
+
logEvent("option_tap", option);
|
|
2035
|
+
send(option);
|
|
2036
|
+
},
|
|
1898
2037
|
style: {
|
|
1899
2038
|
border: `1px solid ${t2.inputBorder}`,
|
|
1900
2039
|
background: "transparent",
|
|
@@ -2096,7 +2235,7 @@ function AssistSheet({
|
|
|
2096
2235
|
"button",
|
|
2097
2236
|
{
|
|
2098
2237
|
type: "button",
|
|
2099
|
-
onClick:
|
|
2238
|
+
onClick: keepChatting,
|
|
2100
2239
|
style: {
|
|
2101
2240
|
alignSelf: "flex-start",
|
|
2102
2241
|
border: "none",
|
|
@@ -2231,7 +2370,7 @@ function AssistSheet({
|
|
|
2231
2370
|
{
|
|
2232
2371
|
type: "button",
|
|
2233
2372
|
"data-gg-sheet-send": "",
|
|
2234
|
-
onClick:
|
|
2373
|
+
onClick: sendDraft,
|
|
2235
2374
|
disabled: isSubmitting || !description.trim(),
|
|
2236
2375
|
style: {
|
|
2237
2376
|
width: "100%",
|
|
@@ -2309,7 +2448,10 @@ function AssistSheet({
|
|
|
2309
2448
|
onChange: (e) => {
|
|
2310
2449
|
var _a;
|
|
2311
2450
|
const files = Array.from((_a = e.target.files) != null ? _a : []);
|
|
2312
|
-
if (files.length)
|
|
2451
|
+
if (files.length) {
|
|
2452
|
+
logEvent("image_added", String(files.length));
|
|
2453
|
+
onAddImages(files);
|
|
2454
|
+
}
|
|
2313
2455
|
e.target.value = "";
|
|
2314
2456
|
},
|
|
2315
2457
|
style: { display: "none" }
|
|
@@ -2339,7 +2481,7 @@ function AssistSheet({
|
|
|
2339
2481
|
send(input);
|
|
2340
2482
|
}
|
|
2341
2483
|
},
|
|
2342
|
-
placeholder: "Type your answer\u2026",
|
|
2484
|
+
placeholder: correcting ? "What should change in the draft?" : "Type your answer\u2026",
|
|
2343
2485
|
rows: 1,
|
|
2344
2486
|
disabled: busy,
|
|
2345
2487
|
autoFocus: true,
|
|
@@ -2399,7 +2541,7 @@ function AssistSheet({
|
|
|
2399
2541
|
{
|
|
2400
2542
|
type: "button",
|
|
2401
2543
|
"data-gg-write-myself": "",
|
|
2402
|
-
onClick:
|
|
2544
|
+
onClick: () => leave("write_myself", "footer"),
|
|
2403
2545
|
style: {
|
|
2404
2546
|
display: "block",
|
|
2405
2547
|
margin: "8px auto 0",
|
|
@@ -2471,6 +2613,107 @@ var ATTACHMENT_ACCEPT = [
|
|
|
2471
2613
|
".xlsx",
|
|
2472
2614
|
".zip"
|
|
2473
2615
|
].join(",");
|
|
2616
|
+
var MAX_SCALE = 2;
|
|
2617
|
+
var FRAME_TIMEOUT_MS = 3e3;
|
|
2618
|
+
function canCaptureTabPixels() {
|
|
2619
|
+
var _a;
|
|
2620
|
+
try {
|
|
2621
|
+
return typeof navigator !== "undefined" && typeof ((_a = navigator.mediaDevices) == null ? void 0 : _a.getDisplayMedia) === "function" && typeof globalThis.CaptureController !== "undefined";
|
|
2622
|
+
} catch (e) {
|
|
2623
|
+
return false;
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
var HAVE_CURRENT_DATA = 2;
|
|
2627
|
+
function waitForFrame(video) {
|
|
2628
|
+
if (video.readyState >= HAVE_CURRENT_DATA && video.videoWidth > 0) {
|
|
2629
|
+
return Promise.resolve(true);
|
|
2630
|
+
}
|
|
2631
|
+
return new Promise((resolve) => {
|
|
2632
|
+
const timer = setTimeout(() => resolve(false), FRAME_TIMEOUT_MS);
|
|
2633
|
+
const done = () => {
|
|
2634
|
+
clearTimeout(timer);
|
|
2635
|
+
resolve(true);
|
|
2636
|
+
};
|
|
2637
|
+
if (typeof video.requestVideoFrameCallback === "function") {
|
|
2638
|
+
video.requestVideoFrameCallback(done);
|
|
2639
|
+
} else if (video.readyState >= 2) {
|
|
2640
|
+
done();
|
|
2641
|
+
} else {
|
|
2642
|
+
video.addEventListener("loadeddata", done, { once: true });
|
|
2643
|
+
}
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2646
|
+
async function grabFrame(stream) {
|
|
2647
|
+
const video = document.createElement("video");
|
|
2648
|
+
video.muted = true;
|
|
2649
|
+
video.playsInline = true;
|
|
2650
|
+
video.srcObject = stream;
|
|
2651
|
+
try {
|
|
2652
|
+
await video.play();
|
|
2653
|
+
if (!await waitForFrame(video)) return null;
|
|
2654
|
+
if (!video.videoWidth || !video.videoHeight) return null;
|
|
2655
|
+
const maxWidth = Math.max(1, window.innerWidth) * MAX_SCALE;
|
|
2656
|
+
const factor = Math.min(1, maxWidth / video.videoWidth);
|
|
2657
|
+
const canvas = document.createElement("canvas");
|
|
2658
|
+
canvas.width = Math.round(video.videoWidth * factor);
|
|
2659
|
+
canvas.height = Math.round(video.videoHeight * factor);
|
|
2660
|
+
const ctx = canvas.getContext("2d");
|
|
2661
|
+
if (!ctx) return null;
|
|
2662
|
+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
2663
|
+
return canvas;
|
|
2664
|
+
} finally {
|
|
2665
|
+
video.srcObject = null;
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
async function captureViaTabPixels() {
|
|
2669
|
+
var _a, _b;
|
|
2670
|
+
if (!canCaptureTabPixels()) return null;
|
|
2671
|
+
let stream = null;
|
|
2672
|
+
try {
|
|
2673
|
+
const options = {
|
|
2674
|
+
video: { displaySurface: "browser" },
|
|
2675
|
+
audio: false,
|
|
2676
|
+
preferCurrentTab: true,
|
|
2677
|
+
selfBrowserSurface: "include",
|
|
2678
|
+
surfaceSwitching: "exclude",
|
|
2679
|
+
monitorTypeSurfaces: "exclude"
|
|
2680
|
+
};
|
|
2681
|
+
stream = await navigator.mediaDevices.getDisplayMedia(options);
|
|
2682
|
+
const surface = (_b = (_a = stream.getVideoTracks()[0]) == null ? void 0 : _a.getSettings()) == null ? void 0 : _b.displaySurface;
|
|
2683
|
+
if (surface && surface !== "browser") return null;
|
|
2684
|
+
const canvas = await grabFrame(stream);
|
|
2685
|
+
return canvas ? encodeScreenshot(canvas) : null;
|
|
2686
|
+
} catch (e) {
|
|
2687
|
+
return null;
|
|
2688
|
+
} finally {
|
|
2689
|
+
stream == null ? void 0 : stream.getTracks().forEach((track) => track.stop());
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
async function captureViaHtml2Canvas() {
|
|
2693
|
+
try {
|
|
2694
|
+
const { default: html2canvas } = await import("html2canvas-pro");
|
|
2695
|
+
const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), MAX_SCALE);
|
|
2696
|
+
const canvas = await html2canvas(document.body, {
|
|
2697
|
+
scale,
|
|
2698
|
+
logging: false,
|
|
2699
|
+
useCORS: true,
|
|
2700
|
+
allowTaint: true,
|
|
2701
|
+
x: window.scrollX,
|
|
2702
|
+
y: window.scrollY,
|
|
2703
|
+
width: window.innerWidth,
|
|
2704
|
+
height: window.innerHeight,
|
|
2705
|
+
windowWidth: window.innerWidth,
|
|
2706
|
+
windowHeight: window.innerHeight
|
|
2707
|
+
});
|
|
2708
|
+
return encodeScreenshot(canvas);
|
|
2709
|
+
} catch (e) {
|
|
2710
|
+
return null;
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
async function captureDefaultScreenshot() {
|
|
2714
|
+
var _a;
|
|
2715
|
+
return (_a = await captureViaTabPixels()) != null ? _a : await captureViaHtml2Canvas();
|
|
2716
|
+
}
|
|
2474
2717
|
var SEVERITY_REQUIRED = "Pick how bad it is before sending.";
|
|
2475
2718
|
function useIsDark() {
|
|
2476
2719
|
if (typeof window === "undefined") return true;
|
|
@@ -2745,27 +2988,6 @@ function isLowQualityText(text) {
|
|
|
2745
2988
|
}
|
|
2746
2989
|
return null;
|
|
2747
2990
|
}
|
|
2748
|
-
async function captureViaHtml2Canvas() {
|
|
2749
|
-
try {
|
|
2750
|
-
const { default: html2canvas } = await import("html2canvas-pro");
|
|
2751
|
-
const scale = Math.min(Math.max(window.devicePixelRatio || 1, 1), 2);
|
|
2752
|
-
const canvas = await html2canvas(document.body, {
|
|
2753
|
-
scale,
|
|
2754
|
-
logging: false,
|
|
2755
|
-
useCORS: true,
|
|
2756
|
-
allowTaint: true,
|
|
2757
|
-
x: window.scrollX,
|
|
2758
|
-
y: window.scrollY,
|
|
2759
|
-
width: window.innerWidth,
|
|
2760
|
-
height: window.innerHeight,
|
|
2761
|
-
windowWidth: window.innerWidth,
|
|
2762
|
-
windowHeight: window.innerHeight
|
|
2763
|
-
});
|
|
2764
|
-
return encodeScreenshot(canvas);
|
|
2765
|
-
} catch (e) {
|
|
2766
|
-
return null;
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
2991
|
var MIC_MESSAGES = {
|
|
2770
2992
|
blocked: "Microphone is blocked for this site. Allow it in your browser's site settings, then reload this page. You can type your report instead.",
|
|
2771
2993
|
notFound: "No microphone found. Connect one and try again, or type your report instead.",
|
|
@@ -2803,7 +3025,7 @@ function ReportDialog({
|
|
|
2803
3025
|
transcribeAudio: transcribeAudio2,
|
|
2804
3026
|
types,
|
|
2805
3027
|
showSeverity = true,
|
|
2806
|
-
captureScreenshot =
|
|
3028
|
+
captureScreenshot = captureDefaultScreenshot,
|
|
2807
3029
|
reporter,
|
|
2808
3030
|
onClose,
|
|
2809
3031
|
headerSlot
|
|
@@ -2833,6 +3055,7 @@ function ReportDialog({
|
|
|
2833
3055
|
const [isSubmitting, setIsSubmitting] = (0, import_react.useState)(false);
|
|
2834
3056
|
const [submitted, setSubmitted] = (0, import_react.useState)(false);
|
|
2835
3057
|
const [screenshots, setScreenshots] = (0, import_react.useState)([]);
|
|
3058
|
+
const [pageShot, setPageShot] = (0, import_react.useState)(null);
|
|
2836
3059
|
const [attachments, setAttachments] = (0, import_react.useState)([]);
|
|
2837
3060
|
const [previewIndex, setPreviewIndex] = (0, import_react.useState)(null);
|
|
2838
3061
|
const [annotatingIndex, setAnnotatingIndex] = (0, import_react.useState)(null);
|
|
@@ -2998,6 +3221,7 @@ function ReportDialog({
|
|
|
2998
3221
|
setStep(2);
|
|
2999
3222
|
}
|
|
3000
3223
|
const shot = await captureScreenshot();
|
|
3224
|
+
setPageShot(shot != null ? shot : null);
|
|
3001
3225
|
if (shot) setScreenshots([shot]);
|
|
3002
3226
|
if (assist && !assistUsed) setAssistOpen(true);
|
|
3003
3227
|
setIsOpen(true);
|
|
@@ -5195,6 +5419,7 @@ function ReportDialog({
|
|
|
5195
5419
|
imageSrc: screenshots[annotatingIndex],
|
|
5196
5420
|
onCancel: () => setAnnotatingIndex(null),
|
|
5197
5421
|
onSave: (dataUrl) => {
|
|
5422
|
+
if (screenshots[annotatingIndex] === pageShot) setPageShot(dataUrl);
|
|
5198
5423
|
setScreenshots(
|
|
5199
5424
|
(prev) => prev.map((s, i) => i === annotatingIndex ? dataUrl : s)
|
|
5200
5425
|
);
|
|
@@ -5220,6 +5445,7 @@ function ReportDialog({
|
|
|
5220
5445
|
accentText: t2.accentText
|
|
5221
5446
|
},
|
|
5222
5447
|
screenshots,
|
|
5448
|
+
pageShot,
|
|
5223
5449
|
onAddImages: addFiles,
|
|
5224
5450
|
attachmentCount: screenshots.length + attachments.length,
|
|
5225
5451
|
context: { ...assistContext != null ? assistContext : {}, reportType },
|