@jarve/bug-reporter 0.3.0 → 0.3.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/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +134 -67
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +142 -75
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -24,4 +24,4 @@ interface JarveBugReporterProps {
|
|
|
24
24
|
}
|
|
25
25
|
declare function JarveBugReporter({ apiUrl, apiKey, user, buttonPosition, children, }: JarveBugReporterProps): react_jsx_runtime.JSX.Element;
|
|
26
26
|
|
|
27
|
-
export { type BugReporterApiConfig, type BugReporterUser, JarveBugReporter };
|
|
27
|
+
export { type BugReporterApiConfig, type BugReporterUser, type FloatingButtonPosition, JarveBugReporter };
|
package/dist/index.d.ts
CHANGED
|
@@ -24,4 +24,4 @@ interface JarveBugReporterProps {
|
|
|
24
24
|
}
|
|
25
25
|
declare function JarveBugReporter({ apiUrl, apiKey, user, buttonPosition, children, }: JarveBugReporterProps): react_jsx_runtime.JSX.Element;
|
|
26
26
|
|
|
27
|
-
export { type BugReporterApiConfig, type BugReporterUser, JarveBugReporter };
|
|
27
|
+
export { type BugReporterApiConfig, type BugReporterUser, type FloatingButtonPosition, JarveBugReporter };
|
package/dist/index.js
CHANGED
|
@@ -43,9 +43,10 @@ __export(index_exports, {
|
|
|
43
43
|
module.exports = __toCommonJS(index_exports);
|
|
44
44
|
|
|
45
45
|
// src/bug-reporter.tsx
|
|
46
|
-
var
|
|
46
|
+
var import_react4 = require("react");
|
|
47
47
|
|
|
48
48
|
// src/floating-button.tsx
|
|
49
|
+
var import_react = require("react");
|
|
49
50
|
var import_lucide_react = require("lucide-react");
|
|
50
51
|
|
|
51
52
|
// src/cn.ts
|
|
@@ -57,31 +58,97 @@ function cn(...inputs) {
|
|
|
57
58
|
|
|
58
59
|
// src/floating-button.tsx
|
|
59
60
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
61
|
+
var STACK_OFFSET = 56;
|
|
60
62
|
function FloatingButton({ isActive, onClick, position = "right" }) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
const [hovered, setHovered] = (0, import_react.useState)(false);
|
|
64
|
+
const [stackOffset, setStackOffset] = (0, import_react.useState)(0);
|
|
65
|
+
const ref = (0, import_react.useRef)(null);
|
|
66
|
+
const isLeft = position === "left";
|
|
67
|
+
const sideClasses = isLeft ? "left-4 md:left-6" : "right-4 md:right-6";
|
|
68
|
+
(0, import_react.useEffect)(() => {
|
|
69
|
+
const el = ref.current;
|
|
70
|
+
if (!el) return;
|
|
71
|
+
let rafId;
|
|
72
|
+
const recalculate = () => {
|
|
73
|
+
const widgets = Array.from(
|
|
74
|
+
document.querySelectorAll(`[data-jarve-widget][data-jarve-position="${position}"]`)
|
|
75
|
+
);
|
|
76
|
+
widgets.sort(
|
|
77
|
+
(a, b) => (a.getAttribute("data-jarve-widget") || "").localeCompare(
|
|
78
|
+
b.getAttribute("data-jarve-widget") || ""
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
const index = widgets.indexOf(el);
|
|
82
|
+
setStackOffset(index > 0 ? index * STACK_OFFSET : 0);
|
|
83
|
+
};
|
|
84
|
+
recalculate();
|
|
85
|
+
const observer = new MutationObserver(() => {
|
|
86
|
+
cancelAnimationFrame(rafId);
|
|
87
|
+
rafId = requestAnimationFrame(recalculate);
|
|
88
|
+
});
|
|
89
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
90
|
+
return () => {
|
|
91
|
+
observer.disconnect();
|
|
92
|
+
cancelAnimationFrame(rafId);
|
|
93
|
+
};
|
|
94
|
+
}, [position]);
|
|
95
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
96
|
+
"div",
|
|
64
97
|
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
98
|
+
ref,
|
|
99
|
+
"data-jarve-widget": "bug-reporter",
|
|
100
|
+
"data-jarve-position": position,
|
|
101
|
+
className: cn("fixed z-[9999]", "bottom-4 md:bottom-6", sideClasses),
|
|
102
|
+
style: stackOffset > 0 ? { transform: `translateY(-${stackOffset}px)` } : void 0,
|
|
103
|
+
onMouseEnter: () => setHovered(true),
|
|
104
|
+
onMouseLeave: () => setHovered(false),
|
|
105
|
+
children: [
|
|
106
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
107
|
+
"div",
|
|
108
|
+
{
|
|
109
|
+
className: cn(
|
|
110
|
+
"pointer-events-none absolute bottom-full mb-2 w-max max-w-[200px] rounded-lg bg-gray-900 px-3 py-2 text-xs leading-relaxed text-white shadow-lg transition-all duration-200",
|
|
111
|
+
isLeft ? "left-0" : "right-0",
|
|
112
|
+
hovered && !isActive ? "translate-y-0 opacity-100" : "translate-y-1 opacity-0"
|
|
113
|
+
),
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-semibold", children: "Report a bug" }),
|
|
116
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|
|
117
|
+
"Click to screenshot an issue and chat with AI to submit a bug report.",
|
|
118
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
119
|
+
"div",
|
|
120
|
+
{
|
|
121
|
+
className: cn(
|
|
122
|
+
"absolute top-full h-0 w-0 border-x-[6px] border-t-[6px] border-x-transparent border-t-gray-900",
|
|
123
|
+
isLeft ? "left-4" : "right-4"
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
"button",
|
|
132
|
+
{
|
|
133
|
+
onClick,
|
|
134
|
+
className: cn(
|
|
135
|
+
"flex items-center justify-center rounded-full shadow-lg transition-all duration-200",
|
|
136
|
+
"hover:scale-110 focus:ring-2 focus:ring-offset-2 focus:outline-none",
|
|
137
|
+
"h-11 w-11 md:h-12 md:w-12",
|
|
138
|
+
isActive ? "animate-pulse bg-red-500 text-white focus:ring-red-400" : "bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-400"
|
|
139
|
+
),
|
|
140
|
+
title: isActive ? "Cancel bug capture" : "Report a bug",
|
|
141
|
+
"aria-label": isActive ? "Cancel bug capture" : "Report a bug",
|
|
142
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Bug, { className: "h-4 w-4 md:h-5 md:w-5" })
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
]
|
|
79
146
|
}
|
|
80
147
|
);
|
|
81
148
|
}
|
|
82
149
|
|
|
83
150
|
// src/capture-overlay.tsx
|
|
84
|
-
var
|
|
151
|
+
var import_react2 = require("react");
|
|
85
152
|
var import_html_to_image = require("html-to-image");
|
|
86
153
|
|
|
87
154
|
// src/utils.ts
|
|
@@ -410,23 +477,23 @@ function CaptureOverlay({
|
|
|
410
477
|
onCapture,
|
|
411
478
|
onCancel
|
|
412
479
|
}) {
|
|
413
|
-
const [hoveredElement, setHoveredElement] = (0,
|
|
414
|
-
const [hoveredRect, setHoveredRect] = (0,
|
|
415
|
-
const [isCapturing3, setIsCapturing] = (0,
|
|
416
|
-
const [isTouchMode, setIsTouchMode] = (0,
|
|
417
|
-
const [selectedSection, setSelectedSection] = (0,
|
|
418
|
-
const [selectedRect, setSelectedRect] = (0,
|
|
419
|
-
const [selectedTarget, setSelectedTarget] = (0,
|
|
420
|
-
const overlayRef = (0,
|
|
421
|
-
const hoveredElementRef = (0,
|
|
422
|
-
const rafRef = (0,
|
|
423
|
-
const touchCoordsRef = (0,
|
|
424
|
-
(0,
|
|
480
|
+
const [hoveredElement, setHoveredElement] = (0, import_react2.useState)(null);
|
|
481
|
+
const [hoveredRect, setHoveredRect] = (0, import_react2.useState)(null);
|
|
482
|
+
const [isCapturing3, setIsCapturing] = (0, import_react2.useState)(false);
|
|
483
|
+
const [isTouchMode, setIsTouchMode] = (0, import_react2.useState)(false);
|
|
484
|
+
const [selectedSection, setSelectedSection] = (0, import_react2.useState)(null);
|
|
485
|
+
const [selectedRect, setSelectedRect] = (0, import_react2.useState)(null);
|
|
486
|
+
const [selectedTarget, setSelectedTarget] = (0, import_react2.useState)(null);
|
|
487
|
+
const overlayRef = (0, import_react2.useRef)(null);
|
|
488
|
+
const hoveredElementRef = (0, import_react2.useRef)(null);
|
|
489
|
+
const rafRef = (0, import_react2.useRef)(null);
|
|
490
|
+
const touchCoordsRef = (0, import_react2.useRef)(null);
|
|
491
|
+
(0, import_react2.useEffect)(() => {
|
|
425
492
|
if (isActive) {
|
|
426
493
|
setIsTouchMode(isTouchCapable());
|
|
427
494
|
}
|
|
428
495
|
}, [isActive]);
|
|
429
|
-
const captureScreenshot = (0,
|
|
496
|
+
const captureScreenshot = (0, import_react2.useCallback)(
|
|
430
497
|
async (section, target, coords) => {
|
|
431
498
|
const elementInfo = collectElementInfo(target, section, coords);
|
|
432
499
|
setIsCapturing(true);
|
|
@@ -504,7 +571,7 @@ function CaptureOverlay({
|
|
|
504
571
|
},
|
|
505
572
|
[siteId, reporterName, reporterEmail, onCapture]
|
|
506
573
|
);
|
|
507
|
-
const handleMouseMove = (0,
|
|
574
|
+
const handleMouseMove = (0, import_react2.useCallback)(
|
|
508
575
|
(e) => {
|
|
509
576
|
if (!isActive || isCapturing3 || isTouchMode) return;
|
|
510
577
|
if (rafRef.current) return;
|
|
@@ -526,7 +593,7 @@ function CaptureOverlay({
|
|
|
526
593
|
},
|
|
527
594
|
[isActive, isCapturing3, isTouchMode]
|
|
528
595
|
);
|
|
529
|
-
const handleClick = (0,
|
|
596
|
+
const handleClick = (0, import_react2.useCallback)(
|
|
530
597
|
async (e) => {
|
|
531
598
|
if (!isActive || isCapturing3 || isTouchMode) return;
|
|
532
599
|
const target = e.target;
|
|
@@ -540,7 +607,7 @@ function CaptureOverlay({
|
|
|
540
607
|
},
|
|
541
608
|
[isActive, isCapturing3, isTouchMode, captureScreenshot]
|
|
542
609
|
);
|
|
543
|
-
const handleTouchEnd = (0,
|
|
610
|
+
const handleTouchEnd = (0, import_react2.useCallback)(
|
|
544
611
|
(e) => {
|
|
545
612
|
if (!isActive || isCapturing3) return;
|
|
546
613
|
const touch = e.changedTouches[0];
|
|
@@ -557,11 +624,11 @@ function CaptureOverlay({
|
|
|
557
624
|
},
|
|
558
625
|
[isActive, isCapturing3]
|
|
559
626
|
);
|
|
560
|
-
const handleConfirmCapture = (0,
|
|
627
|
+
const handleConfirmCapture = (0, import_react2.useCallback)(async () => {
|
|
561
628
|
if (!selectedSection || !selectedTarget || !touchCoordsRef.current) return;
|
|
562
629
|
await captureScreenshot(selectedSection, selectedTarget, touchCoordsRef.current);
|
|
563
630
|
}, [selectedSection, selectedTarget, captureScreenshot]);
|
|
564
|
-
const handlePointerDown = (0,
|
|
631
|
+
const handlePointerDown = (0, import_react2.useCallback)(
|
|
565
632
|
(e) => {
|
|
566
633
|
if (!isActive) return;
|
|
567
634
|
if (e.pointerType === "touch") {
|
|
@@ -572,7 +639,7 @@ function CaptureOverlay({
|
|
|
572
639
|
},
|
|
573
640
|
[isActive]
|
|
574
641
|
);
|
|
575
|
-
const handleKeyDown = (0,
|
|
642
|
+
const handleKeyDown = (0, import_react2.useCallback)(
|
|
576
643
|
(e) => {
|
|
577
644
|
if (e.key === "Escape" && isActive) {
|
|
578
645
|
e.preventDefault();
|
|
@@ -582,7 +649,7 @@ function CaptureOverlay({
|
|
|
582
649
|
},
|
|
583
650
|
[isActive, onCancel]
|
|
584
651
|
);
|
|
585
|
-
const handleScroll = (0,
|
|
652
|
+
const handleScroll = (0, import_react2.useCallback)(() => {
|
|
586
653
|
if (hoveredElementRef.current) {
|
|
587
654
|
setHoveredRect(hoveredElementRef.current.getBoundingClientRect());
|
|
588
655
|
}
|
|
@@ -590,7 +657,7 @@ function CaptureOverlay({
|
|
|
590
657
|
setSelectedRect(selectedSection.getBoundingClientRect());
|
|
591
658
|
}
|
|
592
659
|
}, [selectedSection]);
|
|
593
|
-
(0,
|
|
660
|
+
(0, import_react2.useEffect)(() => {
|
|
594
661
|
if (!isActive) {
|
|
595
662
|
setHoveredElement(null);
|
|
596
663
|
setHoveredRect(null);
|
|
@@ -712,7 +779,7 @@ function CaptureOverlay({
|
|
|
712
779
|
}
|
|
713
780
|
|
|
714
781
|
// src/report-modal.tsx
|
|
715
|
-
var
|
|
782
|
+
var import_react3 = require("react");
|
|
716
783
|
var import_lucide_react2 = require("lucide-react");
|
|
717
784
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
718
785
|
function ReportModal({
|
|
@@ -723,24 +790,24 @@ function ReportModal({
|
|
|
723
790
|
user,
|
|
724
791
|
onClose
|
|
725
792
|
}) {
|
|
726
|
-
const [messages, setMessages] = (0,
|
|
727
|
-
const [input, setInput] = (0,
|
|
728
|
-
const [isLoading, setIsLoading] = (0,
|
|
729
|
-
const [modalState, setModalState] = (0,
|
|
730
|
-
const [reportId, setReportId] = (0,
|
|
731
|
-
const [screenshotUrl, setScreenshotUrl] = (0,
|
|
732
|
-
const [errorMessage, setErrorMessage] = (0,
|
|
733
|
-
const chatEndRef = (0,
|
|
734
|
-
const inputRef = (0,
|
|
735
|
-
const hasInitRef = (0,
|
|
736
|
-
const apiHeaders = (0,
|
|
793
|
+
const [messages, setMessages] = (0, import_react3.useState)([]);
|
|
794
|
+
const [input, setInput] = (0, import_react3.useState)("");
|
|
795
|
+
const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
|
|
796
|
+
const [modalState, setModalState] = (0, import_react3.useState)("chatting");
|
|
797
|
+
const [reportId, setReportId] = (0, import_react3.useState)(null);
|
|
798
|
+
const [screenshotUrl, setScreenshotUrl] = (0, import_react3.useState)(null);
|
|
799
|
+
const [errorMessage, setErrorMessage] = (0, import_react3.useState)(null);
|
|
800
|
+
const chatEndRef = (0, import_react3.useRef)(null);
|
|
801
|
+
const inputRef = (0, import_react3.useRef)(null);
|
|
802
|
+
const hasInitRef = (0, import_react3.useRef)(false);
|
|
803
|
+
const apiHeaders = (0, import_react3.useMemo)(
|
|
737
804
|
() => ({
|
|
738
805
|
"Content-Type": "application/json",
|
|
739
806
|
"X-Bug-Reporter-Key": apiConfig.apiKey
|
|
740
807
|
}),
|
|
741
808
|
[apiConfig.apiKey]
|
|
742
809
|
);
|
|
743
|
-
(0,
|
|
810
|
+
(0, import_react3.useEffect)(() => {
|
|
744
811
|
if ((captureResult == null ? void 0 : captureResult.screenshot) && captureResult.screenshot.size > 0) {
|
|
745
812
|
const url = URL.createObjectURL(captureResult.screenshot);
|
|
746
813
|
setScreenshotUrl((prev) => {
|
|
@@ -757,7 +824,7 @@ function ReportModal({
|
|
|
757
824
|
return null;
|
|
758
825
|
});
|
|
759
826
|
}, [captureResult]);
|
|
760
|
-
const sendInitialMessage = (0,
|
|
827
|
+
const sendInitialMessage = (0, import_react3.useCallback)(async () => {
|
|
761
828
|
if (!captureResult) return;
|
|
762
829
|
setIsLoading(true);
|
|
763
830
|
try {
|
|
@@ -798,23 +865,23 @@ function ReportModal({
|
|
|
798
865
|
setIsLoading(false);
|
|
799
866
|
}
|
|
800
867
|
}, [captureResult, apiConfig.apiUrl, apiHeaders]);
|
|
801
|
-
(0,
|
|
868
|
+
(0, import_react3.useEffect)(() => {
|
|
802
869
|
if (isOpen && captureResult && !hasInitRef.current) {
|
|
803
870
|
hasInitRef.current = true;
|
|
804
871
|
sendInitialMessage();
|
|
805
872
|
}
|
|
806
873
|
}, [isOpen, captureResult, sendInitialMessage]);
|
|
807
|
-
(0,
|
|
874
|
+
(0, import_react3.useEffect)(() => {
|
|
808
875
|
var _a;
|
|
809
876
|
(_a = chatEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
810
877
|
}, [messages]);
|
|
811
|
-
(0,
|
|
878
|
+
(0, import_react3.useEffect)(() => {
|
|
812
879
|
var _a;
|
|
813
880
|
if (isOpen && !isLoading) {
|
|
814
881
|
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
815
882
|
}
|
|
816
883
|
}, [isOpen, isLoading, messages]);
|
|
817
|
-
const submitReport = (0,
|
|
884
|
+
const submitReport = (0, import_react3.useCallback)(
|
|
818
885
|
async (conversation, structuredReport) => {
|
|
819
886
|
if (!captureResult || modalState !== "chatting") return;
|
|
820
887
|
setModalState("submitting");
|
|
@@ -878,7 +945,7 @@ function ReportModal({
|
|
|
878
945
|
},
|
|
879
946
|
[captureResult, apiConfig.apiUrl, apiHeaders, modalState]
|
|
880
947
|
);
|
|
881
|
-
const handleManualSubmit = (0,
|
|
948
|
+
const handleManualSubmit = (0, import_react3.useCallback)(() => {
|
|
882
949
|
submitReport(messages);
|
|
883
950
|
}, [submitReport, messages]);
|
|
884
951
|
async function sendMessage() {
|
|
@@ -1113,10 +1180,10 @@ function JarveBugReporter({
|
|
|
1113
1180
|
children
|
|
1114
1181
|
}) {
|
|
1115
1182
|
const safeApiKey = apiKey || "";
|
|
1116
|
-
const [captureMode, setCaptureMode] = (0,
|
|
1117
|
-
const [captureResult, setCaptureResult] = (0,
|
|
1118
|
-
const [showModal, setShowModal] = (0,
|
|
1119
|
-
(0,
|
|
1183
|
+
const [captureMode, setCaptureMode] = (0, import_react4.useState)(false);
|
|
1184
|
+
const [captureResult, setCaptureResult] = (0, import_react4.useState)(null);
|
|
1185
|
+
const [showModal, setShowModal] = (0, import_react4.useState)(false);
|
|
1186
|
+
(0, import_react4.useEffect)(() => {
|
|
1120
1187
|
startCapturing();
|
|
1121
1188
|
startNetworkCapture();
|
|
1122
1189
|
return () => {
|
|
@@ -1124,18 +1191,18 @@ function JarveBugReporter({
|
|
|
1124
1191
|
stopNetworkCapture();
|
|
1125
1192
|
};
|
|
1126
1193
|
}, []);
|
|
1127
|
-
const toggleCaptureMode = (0,
|
|
1194
|
+
const toggleCaptureMode = (0, import_react4.useCallback)(() => {
|
|
1128
1195
|
setCaptureMode((prev) => !prev);
|
|
1129
1196
|
}, []);
|
|
1130
|
-
const handleCapture = (0,
|
|
1197
|
+
const handleCapture = (0, import_react4.useCallback)((result) => {
|
|
1131
1198
|
setCaptureResult(result);
|
|
1132
1199
|
setCaptureMode(false);
|
|
1133
1200
|
setShowModal(true);
|
|
1134
1201
|
}, []);
|
|
1135
|
-
const handleCancelCapture = (0,
|
|
1202
|
+
const handleCancelCapture = (0, import_react4.useCallback)(() => {
|
|
1136
1203
|
setCaptureMode(false);
|
|
1137
1204
|
}, []);
|
|
1138
|
-
const handleCloseModal = (0,
|
|
1205
|
+
const handleCloseModal = (0, import_react4.useCallback)(() => {
|
|
1139
1206
|
setShowModal(false);
|
|
1140
1207
|
setCaptureResult(null);
|
|
1141
1208
|
clearCapturedErrors();
|