@jarve/bug-reporter 0.1.1 → 0.2.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/dist/index.js +198 -95
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +198 -95
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -66,7 +66,7 @@ function FloatingButton({ isActive, onClick }) {
|
|
|
66
66
|
"fixed bottom-6 right-6 z-[9999] flex h-12 w-12 items-center justify-center rounded-full shadow-lg transition-all duration-200",
|
|
67
67
|
"hover:scale-110 focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
68
68
|
isActive ? "bg-red-500 text-white animate-pulse focus:ring-red-400" : "bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-400",
|
|
69
|
-
"bottom-4 right-4 h-
|
|
69
|
+
"bottom-4 right-4 h-11 w-11 md:bottom-6 md:right-6 md:h-12 md:w-12"
|
|
70
70
|
),
|
|
71
71
|
title: isActive ? "Cancel bug capture" : "Report a bug",
|
|
72
72
|
"aria-label": isActive ? "Cancel bug capture" : "Report a bug",
|
|
@@ -134,7 +134,18 @@ function buildSelectorPath(element, stopAt) {
|
|
|
134
134
|
}
|
|
135
135
|
return parts.join(" > ");
|
|
136
136
|
}
|
|
137
|
-
function
|
|
137
|
+
function isTouchCapable() {
|
|
138
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
139
|
+
}
|
|
140
|
+
function extractCoordinates(e) {
|
|
141
|
+
return {
|
|
142
|
+
pageX: e.pageX,
|
|
143
|
+
pageY: e.pageY,
|
|
144
|
+
clientX: e.clientX,
|
|
145
|
+
clientY: e.clientY
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function collectElementInfo(target, section, coords) {
|
|
138
149
|
const sectionRect = section.getBoundingClientRect();
|
|
139
150
|
const dataAttributes = {};
|
|
140
151
|
for (const attr of Array.from(target.attributes)) {
|
|
@@ -150,10 +161,10 @@ function collectElementInfo(target, section, event) {
|
|
|
150
161
|
ariaLabel: target.getAttribute("aria-label") || null,
|
|
151
162
|
dataAttributes,
|
|
152
163
|
selectorPath: buildSelectorPath(target, section),
|
|
153
|
-
clickX:
|
|
154
|
-
clickY:
|
|
155
|
-
relativeClickX:
|
|
156
|
-
relativeClickY:
|
|
164
|
+
clickX: coords.pageX,
|
|
165
|
+
clickY: coords.pageY,
|
|
166
|
+
relativeClickX: coords.clientX - sectionRect.left,
|
|
167
|
+
relativeClickY: coords.clientY - sectionRect.top
|
|
157
168
|
};
|
|
158
169
|
}
|
|
159
170
|
function collectMetadata(sectionElement, siteId, reporterName, reporterEmail, clickedElement) {
|
|
@@ -378,6 +389,15 @@ function clearCapturedNetworkErrors() {
|
|
|
378
389
|
|
|
379
390
|
// src/capture-overlay.tsx
|
|
380
391
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
392
|
+
function dataUrlToBlob(dataUrl) {
|
|
393
|
+
var _a;
|
|
394
|
+
const [header, base64] = dataUrl.split(",");
|
|
395
|
+
const mime = ((_a = header.match(/:(.*?);/)) == null ? void 0 : _a[1]) || "image/png";
|
|
396
|
+
const bytes = atob(base64);
|
|
397
|
+
const arr = new Uint8Array(bytes.length);
|
|
398
|
+
for (let i = 0; i < bytes.length; i++) arr[i] = bytes.charCodeAt(i);
|
|
399
|
+
return new Blob([arr], { type: mime });
|
|
400
|
+
}
|
|
381
401
|
function CaptureOverlay({
|
|
382
402
|
isActive,
|
|
383
403
|
siteId,
|
|
@@ -389,48 +409,30 @@ function CaptureOverlay({
|
|
|
389
409
|
const [hoveredElement, setHoveredElement] = (0, import_react.useState)(null);
|
|
390
410
|
const [hoveredRect, setHoveredRect] = (0, import_react.useState)(null);
|
|
391
411
|
const [isCapturing3, setIsCapturing] = (0, import_react.useState)(false);
|
|
412
|
+
const [isTouchMode, setIsTouchMode] = (0, import_react.useState)(false);
|
|
413
|
+
const [selectedSection, setSelectedSection] = (0, import_react.useState)(null);
|
|
414
|
+
const [selectedRect, setSelectedRect] = (0, import_react.useState)(null);
|
|
415
|
+
const [selectedTarget, setSelectedTarget] = (0, import_react.useState)(null);
|
|
392
416
|
const overlayRef = (0, import_react.useRef)(null);
|
|
393
417
|
const hoveredElementRef = (0, import_react.useRef)(null);
|
|
394
418
|
const rafRef = (0, import_react.useRef)(null);
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
setHoveredElement(null);
|
|
405
|
-
setHoveredRect(null);
|
|
406
|
-
hoveredElementRef.current = null;
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
const section = getNearestSection(target);
|
|
410
|
-
setHoveredElement(section);
|
|
411
|
-
hoveredElementRef.current = section;
|
|
412
|
-
setHoveredRect(section ? section.getBoundingClientRect() : null);
|
|
413
|
-
});
|
|
414
|
-
},
|
|
415
|
-
[isActive, isCapturing3]
|
|
416
|
-
);
|
|
417
|
-
const handleClick = (0, import_react.useCallback)(
|
|
418
|
-
async (e) => {
|
|
419
|
-
var _a, _b;
|
|
420
|
-
if (!isActive || isCapturing3) return;
|
|
421
|
-
const target = e.target;
|
|
422
|
-
if (!(target instanceof HTMLElement)) return;
|
|
423
|
-
if (target.closest("[data-bug-reporter]")) return;
|
|
424
|
-
e.preventDefault();
|
|
425
|
-
e.stopPropagation();
|
|
426
|
-
const section = getNearestSection(target);
|
|
427
|
-
if (!section) return;
|
|
428
|
-
const elementInfo = collectElementInfo(target, section, e);
|
|
419
|
+
const touchCoordsRef = (0, import_react.useRef)(null);
|
|
420
|
+
(0, import_react.useEffect)(() => {
|
|
421
|
+
if (isActive) {
|
|
422
|
+
setIsTouchMode(isTouchCapable());
|
|
423
|
+
}
|
|
424
|
+
}, [isActive]);
|
|
425
|
+
const captureScreenshot = (0, import_react.useCallback)(
|
|
426
|
+
async (section, target, coords) => {
|
|
427
|
+
const elementInfo = collectElementInfo(target, section, coords);
|
|
429
428
|
setIsCapturing(true);
|
|
430
429
|
try {
|
|
431
430
|
setHoveredElement(null);
|
|
432
431
|
setHoveredRect(null);
|
|
433
432
|
hoveredElementRef.current = null;
|
|
433
|
+
setSelectedSection(null);
|
|
434
|
+
setSelectedRect(null);
|
|
435
|
+
setSelectedTarget(null);
|
|
434
436
|
await new Promise((r) => setTimeout(r, 50));
|
|
435
437
|
const MAX_DIMENSION = 2e3;
|
|
436
438
|
const sectionRect = section.getBoundingClientRect();
|
|
@@ -440,19 +442,8 @@ function CaptureOverlay({
|
|
|
440
442
|
pixelRatio,
|
|
441
443
|
skipFonts: true
|
|
442
444
|
});
|
|
443
|
-
const
|
|
444
|
-
const
|
|
445
|
-
const bytes = atob(base64);
|
|
446
|
-
const arr = new Uint8Array(bytes.length);
|
|
447
|
-
for (let i = 0; i < bytes.length; i++) arr[i] = bytes.charCodeAt(i);
|
|
448
|
-
const blob = new Blob([arr], { type: mime });
|
|
449
|
-
const metadata = collectMetadata(
|
|
450
|
-
section,
|
|
451
|
-
siteId,
|
|
452
|
-
reporterName,
|
|
453
|
-
reporterEmail,
|
|
454
|
-
elementInfo
|
|
455
|
-
);
|
|
445
|
+
const blob = dataUrlToBlob(dataUrl);
|
|
446
|
+
const metadata = collectMetadata(section, siteId, reporterName, reporterEmail, elementInfo);
|
|
456
447
|
const consoleErrors = getCapturedErrors();
|
|
457
448
|
const networkErrors = getCapturedNetworkErrors();
|
|
458
449
|
onCapture({ screenshot: blob, metadata, consoleErrors, networkErrors });
|
|
@@ -465,31 +456,14 @@ function CaptureOverlay({
|
|
|
465
456
|
skipFonts: true,
|
|
466
457
|
cacheBust: true
|
|
467
458
|
});
|
|
468
|
-
const
|
|
469
|
-
const
|
|
470
|
-
const bytes = atob(base64);
|
|
471
|
-
const arr = new Uint8Array(bytes.length);
|
|
472
|
-
for (let i = 0; i < bytes.length; i++) arr[i] = bytes.charCodeAt(i);
|
|
473
|
-
const retryBlob = new Blob([arr], { type: mime });
|
|
474
|
-
const metadata = collectMetadata(
|
|
475
|
-
section,
|
|
476
|
-
siteId,
|
|
477
|
-
reporterName,
|
|
478
|
-
reporterEmail,
|
|
479
|
-
elementInfo
|
|
480
|
-
);
|
|
459
|
+
const retryBlob = dataUrlToBlob(dataUrl);
|
|
460
|
+
const metadata = collectMetadata(section, siteId, reporterName, reporterEmail, elementInfo);
|
|
481
461
|
const consoleErrors = getCapturedErrors();
|
|
482
462
|
const networkErrors = getCapturedNetworkErrors();
|
|
483
463
|
onCapture({ screenshot: retryBlob, metadata, consoleErrors, networkErrors });
|
|
484
|
-
} catch (
|
|
464
|
+
} catch (e) {
|
|
485
465
|
console.error("Bug reporter: screenshot capture failed after retry");
|
|
486
|
-
const metadata = collectMetadata(
|
|
487
|
-
section,
|
|
488
|
-
siteId,
|
|
489
|
-
reporterName,
|
|
490
|
-
reporterEmail,
|
|
491
|
-
elementInfo
|
|
492
|
-
);
|
|
466
|
+
const metadata = collectMetadata(section, siteId, reporterName, reporterEmail, elementInfo);
|
|
493
467
|
const consoleErrors = getCapturedErrors();
|
|
494
468
|
const networkErrors = getCapturedNetworkErrors();
|
|
495
469
|
onCapture({
|
|
@@ -503,7 +477,75 @@ function CaptureOverlay({
|
|
|
503
477
|
setIsCapturing(false);
|
|
504
478
|
}
|
|
505
479
|
},
|
|
506
|
-
[
|
|
480
|
+
[siteId, reporterName, reporterEmail, onCapture]
|
|
481
|
+
);
|
|
482
|
+
const handleMouseMove = (0, import_react.useCallback)(
|
|
483
|
+
(e) => {
|
|
484
|
+
if (!isActive || isCapturing3 || isTouchMode) return;
|
|
485
|
+
if (rafRef.current) return;
|
|
486
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
487
|
+
rafRef.current = null;
|
|
488
|
+
const target = e.target;
|
|
489
|
+
if (!(target instanceof HTMLElement)) return;
|
|
490
|
+
if (target.closest("[data-bug-reporter]")) {
|
|
491
|
+
setHoveredElement(null);
|
|
492
|
+
setHoveredRect(null);
|
|
493
|
+
hoveredElementRef.current = null;
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const section = getNearestSection(target);
|
|
497
|
+
setHoveredElement(section);
|
|
498
|
+
hoveredElementRef.current = section;
|
|
499
|
+
setHoveredRect(section ? section.getBoundingClientRect() : null);
|
|
500
|
+
});
|
|
501
|
+
},
|
|
502
|
+
[isActive, isCapturing3, isTouchMode]
|
|
503
|
+
);
|
|
504
|
+
const handleClick = (0, import_react.useCallback)(
|
|
505
|
+
async (e) => {
|
|
506
|
+
if (!isActive || isCapturing3 || isTouchMode) return;
|
|
507
|
+
const target = e.target;
|
|
508
|
+
if (!(target instanceof HTMLElement)) return;
|
|
509
|
+
if (target.closest("[data-bug-reporter]")) return;
|
|
510
|
+
e.preventDefault();
|
|
511
|
+
e.stopPropagation();
|
|
512
|
+
const section = getNearestSection(target);
|
|
513
|
+
if (!section) return;
|
|
514
|
+
await captureScreenshot(section, target, extractCoordinates(e));
|
|
515
|
+
},
|
|
516
|
+
[isActive, isCapturing3, isTouchMode, captureScreenshot]
|
|
517
|
+
);
|
|
518
|
+
const handleTouchEnd = (0, import_react.useCallback)(
|
|
519
|
+
(e) => {
|
|
520
|
+
if (!isActive || isCapturing3) return;
|
|
521
|
+
const touch = e.changedTouches[0];
|
|
522
|
+
if (!touch) return;
|
|
523
|
+
const target = document.elementFromPoint(touch.clientX, touch.clientY);
|
|
524
|
+
if (!(target instanceof HTMLElement)) return;
|
|
525
|
+
if (target.closest("[data-bug-reporter]")) return;
|
|
526
|
+
const section = getNearestSection(target);
|
|
527
|
+
if (!section) return;
|
|
528
|
+
setSelectedSection(section);
|
|
529
|
+
setSelectedRect(section.getBoundingClientRect());
|
|
530
|
+
setSelectedTarget(target);
|
|
531
|
+
touchCoordsRef.current = extractCoordinates(touch);
|
|
532
|
+
},
|
|
533
|
+
[isActive, isCapturing3]
|
|
534
|
+
);
|
|
535
|
+
const handleConfirmCapture = (0, import_react.useCallback)(async () => {
|
|
536
|
+
if (!selectedSection || !selectedTarget || !touchCoordsRef.current) return;
|
|
537
|
+
await captureScreenshot(selectedSection, selectedTarget, touchCoordsRef.current);
|
|
538
|
+
}, [selectedSection, selectedTarget, captureScreenshot]);
|
|
539
|
+
const handlePointerDown = (0, import_react.useCallback)(
|
|
540
|
+
(e) => {
|
|
541
|
+
if (!isActive) return;
|
|
542
|
+
if (e.pointerType === "touch") {
|
|
543
|
+
setIsTouchMode(true);
|
|
544
|
+
} else if (e.pointerType === "mouse") {
|
|
545
|
+
setIsTouchMode(false);
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
[isActive]
|
|
507
549
|
);
|
|
508
550
|
const handleKeyDown = (0, import_react.useCallback)(
|
|
509
551
|
(e) => {
|
|
@@ -516,60 +558,121 @@ function CaptureOverlay({
|
|
|
516
558
|
[isActive, onCancel]
|
|
517
559
|
);
|
|
518
560
|
const handleScroll = (0, import_react.useCallback)(() => {
|
|
519
|
-
if (
|
|
520
|
-
|
|
521
|
-
|
|
561
|
+
if (hoveredElementRef.current) {
|
|
562
|
+
setHoveredRect(hoveredElementRef.current.getBoundingClientRect());
|
|
563
|
+
}
|
|
564
|
+
if (selectedSection) {
|
|
565
|
+
setSelectedRect(selectedSection.getBoundingClientRect());
|
|
566
|
+
}
|
|
567
|
+
}, [selectedSection]);
|
|
522
568
|
(0, import_react.useEffect)(() => {
|
|
523
569
|
if (!isActive) {
|
|
524
570
|
setHoveredElement(null);
|
|
525
571
|
setHoveredRect(null);
|
|
526
572
|
hoveredElementRef.current = null;
|
|
573
|
+
setSelectedSection(null);
|
|
574
|
+
setSelectedRect(null);
|
|
575
|
+
setSelectedTarget(null);
|
|
576
|
+
touchCoordsRef.current = null;
|
|
527
577
|
return;
|
|
528
578
|
}
|
|
529
|
-
document.addEventListener("
|
|
530
|
-
document.addEventListener("click", handleClick, true);
|
|
579
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
531
580
|
document.addEventListener("keydown", handleKeyDown);
|
|
532
581
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
582
|
+
if (isTouchMode) {
|
|
583
|
+
document.addEventListener("touchend", handleTouchEnd, { passive: true });
|
|
584
|
+
} else {
|
|
585
|
+
document.addEventListener("mousemove", handleMouseMove, true);
|
|
586
|
+
document.addEventListener("click", handleClick, true);
|
|
587
|
+
}
|
|
533
588
|
return () => {
|
|
534
|
-
document.removeEventListener("
|
|
535
|
-
document.removeEventListener("click", handleClick, true);
|
|
589
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
536
590
|
document.removeEventListener("keydown", handleKeyDown);
|
|
537
591
|
window.removeEventListener("scroll", handleScroll);
|
|
592
|
+
document.removeEventListener("touchend", handleTouchEnd);
|
|
593
|
+
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
594
|
+
document.removeEventListener("click", handleClick, true);
|
|
538
595
|
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
539
596
|
};
|
|
540
|
-
}, [isActive, handleMouseMove, handleClick, handleKeyDown, handleScroll]);
|
|
541
|
-
|
|
597
|
+
}, [isActive, isTouchMode, handleMouseMove, handleClick, handleTouchEnd, handlePointerDown, handleKeyDown, handleScroll]);
|
|
598
|
+
const highlightRect = isTouchMode ? selectedRect : hoveredRect;
|
|
599
|
+
const showHighlight = isTouchMode ? !!selectedSection : !!hoveredElement && !!hoveredRect;
|
|
600
|
+
if (!isActive) return null;
|
|
542
601
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
543
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
602
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
544
603
|
"div",
|
|
545
604
|
{
|
|
546
605
|
"data-bug-reporter": true,
|
|
547
606
|
role: "alert",
|
|
548
607
|
"aria-live": "assertive",
|
|
549
|
-
className: "fixed top-0 left-0 right-0 z-[10000] bg-indigo-600 text-white text-center py-2 px-4 text-sm font-medium",
|
|
550
|
-
children: [
|
|
608
|
+
className: "fixed top-0 left-0 right-0 z-[10000] bg-indigo-600 text-white text-center py-2 px-4 text-sm font-medium flex items-center justify-center gap-3",
|
|
609
|
+
children: isTouchMode ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
610
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Tap the section with the bug" }),
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
612
|
+
"button",
|
|
613
|
+
{
|
|
614
|
+
onClick: onCancel,
|
|
615
|
+
className: "px-3 py-1 min-h-[44px] bg-white/20 rounded-md text-sm font-medium",
|
|
616
|
+
children: "Cancel"
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
551
620
|
"Click on the section with the bug. Press ",
|
|
552
621
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("kbd", { className: "px-1.5 py-0.5 bg-indigo-800 rounded text-xs mx-1", children: "Esc" }),
|
|
553
622
|
" to cancel."
|
|
554
|
-
]
|
|
623
|
+
] })
|
|
555
624
|
}
|
|
556
625
|
),
|
|
557
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
626
|
+
showHighlight && highlightRect && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
558
627
|
"div",
|
|
559
628
|
{
|
|
560
629
|
ref: overlayRef,
|
|
561
630
|
"data-bug-reporter": true,
|
|
562
631
|
className: "fixed pointer-events-none z-[9998] border-2 border-indigo-500 rounded-sm transition-all duration-150 ease-out",
|
|
563
632
|
style: {
|
|
564
|
-
top:
|
|
565
|
-
left:
|
|
566
|
-
width:
|
|
567
|
-
height:
|
|
633
|
+
top: highlightRect.top - 2,
|
|
634
|
+
left: highlightRect.left - 2,
|
|
635
|
+
width: highlightRect.width + 4,
|
|
636
|
+
height: highlightRect.height + 4,
|
|
568
637
|
backgroundColor: "rgba(99, 102, 241, 0.08)"
|
|
569
638
|
}
|
|
570
639
|
}
|
|
571
640
|
),
|
|
572
|
-
|
|
641
|
+
isTouchMode && selectedSection && !isCapturing3 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
642
|
+
"div",
|
|
643
|
+
{
|
|
644
|
+
"data-bug-reporter": true,
|
|
645
|
+
className: "fixed bottom-0 left-0 right-0 z-[10000] bg-white border-t border-gray-200 shadow-lg",
|
|
646
|
+
style: { paddingBottom: "env(safe-area-inset-bottom, 0px)" },
|
|
647
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between px-4 py-3 gap-3", children: [
|
|
648
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm font-medium text-gray-900 truncate", children: "Capture this section?" }),
|
|
649
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex gap-2 shrink-0", children: [
|
|
650
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
651
|
+
"button",
|
|
652
|
+
{
|
|
653
|
+
onClick: () => {
|
|
654
|
+
setSelectedSection(null);
|
|
655
|
+
setSelectedRect(null);
|
|
656
|
+
setSelectedTarget(null);
|
|
657
|
+
touchCoordsRef.current = null;
|
|
658
|
+
},
|
|
659
|
+
className: "px-4 min-h-[44px] rounded-md border border-gray-300 text-sm font-medium text-gray-700",
|
|
660
|
+
children: "Cancel"
|
|
661
|
+
}
|
|
662
|
+
),
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
664
|
+
"button",
|
|
665
|
+
{
|
|
666
|
+
onClick: handleConfirmCapture,
|
|
667
|
+
className: "px-4 min-h-[44px] rounded-md bg-indigo-600 text-white text-sm font-medium",
|
|
668
|
+
children: "Capture"
|
|
669
|
+
}
|
|
670
|
+
)
|
|
671
|
+
] })
|
|
672
|
+
] })
|
|
673
|
+
}
|
|
674
|
+
),
|
|
675
|
+
!isTouchMode && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `* { cursor: crosshair !important; }` })
|
|
573
676
|
] });
|
|
574
677
|
}
|
|
575
678
|
|
|
@@ -814,7 +917,7 @@ function ReportModal({
|
|
|
814
917
|
onClose();
|
|
815
918
|
}
|
|
816
919
|
function handleKeyDown(e) {
|
|
817
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
920
|
+
if (e.key === "Enter" && !e.shiftKey && !isTouchCapable()) {
|
|
818
921
|
e.preventDefault();
|
|
819
922
|
sendMessage();
|
|
820
923
|
}
|