@jarve/bug-reporter 0.3.0 → 0.3.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/index.mjs CHANGED
@@ -20,9 +20,10 @@ var __spreadValues = (a, b) => {
20
20
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
21
 
22
22
  // src/bug-reporter.tsx
23
- import { useState as useState3, useEffect as useEffect3, useCallback as useCallback3 } from "react";
23
+ import { useState as useState4, useEffect as useEffect3, useCallback as useCallback3 } from "react";
24
24
 
25
25
  // src/floating-button.tsx
26
+ import { useState } from "react";
26
27
  import { Bug } from "lucide-react";
27
28
 
28
29
  // src/cn.ts
@@ -33,32 +34,64 @@ function cn(...inputs) {
33
34
  }
34
35
 
35
36
  // src/floating-button.tsx
36
- import { jsx } from "react/jsx-runtime";
37
+ import { jsx, jsxs } from "react/jsx-runtime";
37
38
  function FloatingButton({ isActive, onClick, position = "right" }) {
38
- const sideClasses = position === "left" ? "left-4 md:left-6" : "right-4 md:right-6";
39
- return /* @__PURE__ */ jsx(
40
- "button",
39
+ const [hovered, setHovered] = useState(false);
40
+ const isLeft = position === "left";
41
+ const sideClasses = isLeft ? "left-4 md:left-6" : "right-4 md:right-6";
42
+ return /* @__PURE__ */ jsxs(
43
+ "div",
41
44
  {
42
- onClick,
43
- className: cn(
44
- "fixed z-[9999] flex items-center justify-center rounded-full shadow-lg transition-all duration-200",
45
- "hover:scale-110 focus:ring-2 focus:ring-offset-2 focus:outline-none",
46
- // size + vertical position
47
- "bottom-4 h-11 w-11 md:bottom-6 md:h-12 md:w-12",
48
- // horizontal side
49
- sideClasses,
50
- // active vs idle colors
51
- 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"
52
- ),
53
- title: isActive ? "Cancel bug capture" : "Report a bug",
54
- "aria-label": isActive ? "Cancel bug capture" : "Report a bug",
55
- children: /* @__PURE__ */ jsx(Bug, { className: "h-4 w-4 md:h-5 md:w-5" })
45
+ className: cn("fixed z-[9999]", "bottom-4 md:bottom-6", sideClasses),
46
+ onMouseEnter: () => setHovered(true),
47
+ onMouseLeave: () => setHovered(false),
48
+ children: [
49
+ /* @__PURE__ */ jsxs(
50
+ "div",
51
+ {
52
+ className: cn(
53
+ "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",
54
+ isLeft ? "left-0" : "right-0",
55
+ hovered && !isActive ? "translate-y-0 opacity-100" : "translate-y-1 opacity-0"
56
+ ),
57
+ children: [
58
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: "Report a bug" }),
59
+ /* @__PURE__ */ jsx("br", {}),
60
+ "Click to screenshot an issue and chat with AI to submit a bug report.",
61
+ /* @__PURE__ */ jsx(
62
+ "div",
63
+ {
64
+ className: cn(
65
+ "absolute top-full h-0 w-0 border-x-[6px] border-t-[6px] border-x-transparent border-t-gray-900",
66
+ isLeft ? "left-4" : "right-4"
67
+ )
68
+ }
69
+ )
70
+ ]
71
+ }
72
+ ),
73
+ /* @__PURE__ */ jsx(
74
+ "button",
75
+ {
76
+ onClick,
77
+ className: cn(
78
+ "flex items-center justify-center rounded-full shadow-lg transition-all duration-200",
79
+ "hover:scale-110 focus:ring-2 focus:ring-offset-2 focus:outline-none",
80
+ "h-11 w-11 md:h-12 md:w-12",
81
+ 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"
82
+ ),
83
+ title: isActive ? "Cancel bug capture" : "Report a bug",
84
+ "aria-label": isActive ? "Cancel bug capture" : "Report a bug",
85
+ children: /* @__PURE__ */ jsx(Bug, { className: "h-4 w-4 md:h-5 md:w-5" })
86
+ }
87
+ )
88
+ ]
56
89
  }
57
90
  );
58
91
  }
59
92
 
60
93
  // src/capture-overlay.tsx
61
- import { useEffect, useState, useCallback, useRef } from "react";
94
+ import { useEffect, useState as useState2, useCallback, useRef } from "react";
62
95
  import { toPng } from "html-to-image";
63
96
 
64
97
  // src/utils.ts
@@ -369,7 +402,7 @@ function clearCapturedNetworkErrors() {
369
402
  }
370
403
 
371
404
  // src/capture-overlay.tsx
372
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
405
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
373
406
  function dataUrlToBlob(dataUrl) {
374
407
  var _a;
375
408
  const [header, base64] = dataUrl.split(",");
@@ -387,13 +420,13 @@ function CaptureOverlay({
387
420
  onCapture,
388
421
  onCancel
389
422
  }) {
390
- const [hoveredElement, setHoveredElement] = useState(null);
391
- const [hoveredRect, setHoveredRect] = useState(null);
392
- const [isCapturing3, setIsCapturing] = useState(false);
393
- const [isTouchMode, setIsTouchMode] = useState(false);
394
- const [selectedSection, setSelectedSection] = useState(null);
395
- const [selectedRect, setSelectedRect] = useState(null);
396
- const [selectedTarget, setSelectedTarget] = useState(null);
423
+ const [hoveredElement, setHoveredElement] = useState2(null);
424
+ const [hoveredRect, setHoveredRect] = useState2(null);
425
+ const [isCapturing3, setIsCapturing] = useState2(false);
426
+ const [isTouchMode, setIsTouchMode] = useState2(false);
427
+ const [selectedSection, setSelectedSection] = useState2(null);
428
+ const [selectedRect, setSelectedRect] = useState2(null);
429
+ const [selectedTarget, setSelectedTarget] = useState2(null);
397
430
  const overlayRef = useRef(null);
398
431
  const hoveredElementRef = useRef(null);
399
432
  const rafRef = useRef(null);
@@ -609,7 +642,7 @@ function CaptureOverlay({
609
642
  const highlightRect = isTouchMode ? selectedRect : hoveredRect;
610
643
  const showHighlight = isTouchMode ? !!selectedSection : !!hoveredElement && !!hoveredRect;
611
644
  if (!isActive) return null;
612
- return /* @__PURE__ */ jsxs(Fragment, { children: [
645
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
613
646
  /* @__PURE__ */ jsx2(
614
647
  "div",
615
648
  {
@@ -617,7 +650,7 @@ function CaptureOverlay({
617
650
  role: "alert",
618
651
  "aria-live": "assertive",
619
652
  className: "fixed top-0 right-0 left-0 z-[10000] flex items-center justify-center gap-3 bg-indigo-600 px-4 py-2 text-center text-sm font-medium text-white",
620
- children: isTouchMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
653
+ children: isTouchMode ? /* @__PURE__ */ jsxs2(Fragment, { children: [
621
654
  /* @__PURE__ */ jsx2("span", { children: "Tap the section with the bug" }),
622
655
  /* @__PURE__ */ jsx2(
623
656
  "button",
@@ -627,7 +660,7 @@ function CaptureOverlay({
627
660
  children: "Cancel"
628
661
  }
629
662
  )
630
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
663
+ ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
631
664
  "Click on the section with the bug. Press",
632
665
  " ",
633
666
  /* @__PURE__ */ jsx2("kbd", { className: "mx-1 rounded bg-indigo-800 px-1.5 py-0.5 text-xs", children: "Esc" }),
@@ -656,9 +689,9 @@ function CaptureOverlay({
656
689
  "data-bug-reporter": true,
657
690
  className: "fixed right-0 bottom-0 left-0 z-[10000] border-t border-gray-200 bg-white shadow-lg",
658
691
  style: { paddingBottom: "env(safe-area-inset-bottom, 0px)" },
659
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 px-4 py-3", children: [
692
+ children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-3 px-4 py-3", children: [
660
693
  /* @__PURE__ */ jsx2("span", { className: "truncate text-sm font-medium text-gray-900", children: "Capture this section?" }),
661
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 gap-2", children: [
694
+ /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 gap-2", children: [
662
695
  /* @__PURE__ */ jsx2(
663
696
  "button",
664
697
  {
@@ -689,9 +722,9 @@ function CaptureOverlay({
689
722
  }
690
723
 
691
724
  // src/report-modal.tsx
692
- import { useState as useState2, useRef as useRef2, useEffect as useEffect2, useCallback as useCallback2, useMemo } from "react";
725
+ import { useState as useState3, useRef as useRef2, useEffect as useEffect2, useCallback as useCallback2, useMemo } from "react";
693
726
  import { X, Send, Loader2, CheckCircle2 } from "lucide-react";
694
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
727
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
695
728
  function ReportModal({
696
729
  isOpen,
697
730
  captureResult,
@@ -700,13 +733,13 @@ function ReportModal({
700
733
  user,
701
734
  onClose
702
735
  }) {
703
- const [messages, setMessages] = useState2([]);
704
- const [input, setInput] = useState2("");
705
- const [isLoading, setIsLoading] = useState2(false);
706
- const [modalState, setModalState] = useState2("chatting");
707
- const [reportId, setReportId] = useState2(null);
708
- const [screenshotUrl, setScreenshotUrl] = useState2(null);
709
- const [errorMessage, setErrorMessage] = useState2(null);
736
+ const [messages, setMessages] = useState3([]);
737
+ const [input, setInput] = useState3("");
738
+ const [isLoading, setIsLoading] = useState3(false);
739
+ const [modalState, setModalState] = useState3("chatting");
740
+ const [reportId, setReportId] = useState3(null);
741
+ const [screenshotUrl, setScreenshotUrl] = useState3(null);
742
+ const [errorMessage, setErrorMessage] = useState3(null);
710
743
  const chatEndRef = useRef2(null);
711
744
  const inputRef = useRef2(null);
712
745
  const hasInitRef = useRef2(false);
@@ -939,7 +972,7 @@ function ReportModal({
939
972
  onClick: (e) => {
940
973
  if (e.target === e.currentTarget) handleClose();
941
974
  },
942
- children: /* @__PURE__ */ jsxs2(
975
+ children: /* @__PURE__ */ jsxs3(
943
976
  "div",
944
977
  {
945
978
  className: cn(
@@ -949,8 +982,8 @@ function ReportModal({
949
982
  "min-[769px]:max-h-[85vh]"
950
983
  ),
951
984
  children: [
952
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between border-b border-gray-200 bg-gray-50/30 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/30", children: [
953
- /* @__PURE__ */ jsxs2("div", { children: [
985
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between border-b border-gray-200 bg-gray-50/30 px-4 py-3 dark:border-gray-800 dark:bg-gray-900/30", children: [
986
+ /* @__PURE__ */ jsxs3("div", { children: [
954
987
  /* @__PURE__ */ jsx3("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: "Bug Report" }),
955
988
  /* @__PURE__ */ jsx3("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: siteId })
956
989
  ] }),
@@ -972,10 +1005,10 @@ function ReportModal({
972
1005
  className: "max-h-40 w-full rounded-md border border-gray-200 object-contain dark:border-gray-700"
973
1006
  }
974
1007
  ) }),
975
- /* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 space-y-3 overflow-y-auto px-4 py-3", children: modalState === "submitted" ? /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
1008
+ /* @__PURE__ */ jsx3("div", { className: "min-h-0 flex-1 space-y-3 overflow-y-auto px-4 py-3", children: modalState === "submitted" ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
976
1009
  /* @__PURE__ */ jsx3(CheckCircle2, { className: "mb-3 h-12 w-12 text-green-500" }),
977
1010
  /* @__PURE__ */ jsx3("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Report Submitted" }),
978
- /* @__PURE__ */ jsxs2("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: [
1011
+ /* @__PURE__ */ jsxs3("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: [
979
1012
  "Reference:",
980
1013
  " ",
981
1014
  /* @__PURE__ */ jsx3("code", { className: "rounded bg-gray-100 px-1.5 py-0.5 text-xs dark:bg-gray-800", children: reportId == null ? void 0 : reportId.slice(0, 8) })
@@ -989,7 +1022,7 @@ function ReportModal({
989
1022
  children: "Done"
990
1023
  }
991
1024
  )
992
- ] }) : modalState === "error" ? /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
1025
+ ] }) : modalState === "error" ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-8 text-center", children: [
993
1026
  /* @__PURE__ */ jsx3(X, { className: "mb-3 h-12 w-12 text-red-500" }),
994
1027
  /* @__PURE__ */ jsx3("h3", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Submission Failed" }),
995
1028
  /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: errorMessage || "Something went wrong. Please try again." }),
@@ -1001,10 +1034,10 @@ function ReportModal({
1001
1034
  children: "Try Again"
1002
1035
  }
1003
1036
  )
1004
- ] }) : modalState === "submitting" ? /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center py-8", children: [
1037
+ ] }) : modalState === "submitting" ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-8", children: [
1005
1038
  /* @__PURE__ */ jsx3(Loader2, { className: "mb-3 h-8 w-8 animate-spin text-indigo-500" }),
1006
1039
  /* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Submitting your report..." })
1007
- ] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
1040
+ ] }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
1008
1041
  (captureResult == null ? void 0 : captureResult.screenshot.size) === 0 && /* @__PURE__ */ jsx3("p", { className: "text-xs text-amber-600", children: "Screenshot could not be captured. Please describe the visual issue in detail." }),
1009
1042
  messages.map((msg, i) => /* @__PURE__ */ jsx3(
1010
1043
  "div",
@@ -1017,13 +1050,13 @@ function ReportModal({
1017
1050
  },
1018
1051
  i
1019
1052
  )),
1020
- isLoading && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 rounded-lg bg-gray-100/50 p-3 dark:bg-gray-800/50", children: [
1053
+ isLoading && /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 rounded-lg bg-gray-100/50 p-3 dark:bg-gray-800/50", children: [
1021
1054
  /* @__PURE__ */ jsx3(Loader2, { className: "h-3.5 w-3.5 animate-spin text-gray-500" }),
1022
1055
  /* @__PURE__ */ jsx3("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Thinking..." })
1023
1056
  ] }),
1024
1057
  /* @__PURE__ */ jsx3("div", { ref: chatEndRef })
1025
1058
  ] }) }),
1026
- modalState === "chatting" && /* @__PURE__ */ jsx3("div", { className: "border-t border-gray-200 px-4 py-3 dark:border-gray-800", children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2", children: [
1059
+ modalState === "chatting" && /* @__PURE__ */ jsx3("div", { className: "border-t border-gray-200 px-4 py-3 dark:border-gray-800", children: /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-2", children: [
1027
1060
  /* @__PURE__ */ jsx3(
1028
1061
  "textarea",
1029
1062
  {
@@ -1037,8 +1070,8 @@ function ReportModal({
1037
1070
  disabled: isLoading
1038
1071
  }
1039
1072
  ),
1040
- /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2", children: [
1041
- captureResult && (captureResult.consoleErrors.length > 0 || captureResult.networkErrors.length > 0) && /* @__PURE__ */ jsxs2("p", { className: "flex-1 text-xs text-amber-600", children: [
1073
+ /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-2", children: [
1074
+ captureResult && (captureResult.consoleErrors.length > 0 || captureResult.networkErrors.length > 0) && /* @__PURE__ */ jsxs3("p", { className: "flex-1 text-xs text-amber-600", children: [
1042
1075
  [
1043
1076
  captureResult.consoleErrors.length > 0 ? `${captureResult.consoleErrors.length} console error${captureResult.consoleErrors.length !== 1 ? "s" : ""}` : null,
1044
1077
  captureResult.networkErrors.length > 0 ? `${captureResult.networkErrors.length} failed request${captureResult.networkErrors.length !== 1 ? "s" : ""}` : null
@@ -1046,8 +1079,8 @@ function ReportModal({
1046
1079
  " ",
1047
1080
  "captured \u2014 these will be included in the report."
1048
1081
  ] }),
1049
- /* @__PURE__ */ jsxs2("div", { className: "flex justify-end gap-2", children: [
1050
- /* @__PURE__ */ jsxs2(
1082
+ /* @__PURE__ */ jsxs3("div", { className: "flex justify-end gap-2", children: [
1083
+ /* @__PURE__ */ jsxs3(
1051
1084
  "button",
1052
1085
  {
1053
1086
  onClick: sendMessage,
@@ -1081,7 +1114,7 @@ function ReportModal({
1081
1114
  }
1082
1115
 
1083
1116
  // src/bug-reporter.tsx
1084
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1117
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1085
1118
  function JarveBugReporter({
1086
1119
  apiUrl,
1087
1120
  apiKey,
@@ -1090,9 +1123,9 @@ function JarveBugReporter({
1090
1123
  children
1091
1124
  }) {
1092
1125
  const safeApiKey = apiKey || "";
1093
- const [captureMode, setCaptureMode] = useState3(false);
1094
- const [captureResult, setCaptureResult] = useState3(null);
1095
- const [showModal, setShowModal] = useState3(false);
1126
+ const [captureMode, setCaptureMode] = useState4(false);
1127
+ const [captureResult, setCaptureResult] = useState4(null);
1128
+ const [showModal, setShowModal] = useState4(false);
1096
1129
  useEffect3(() => {
1097
1130
  startCapturing();
1098
1131
  startNetworkCapture();
@@ -1121,7 +1154,7 @@ function JarveBugReporter({
1121
1154
  const siteId = safeApiKey.startsWith("brk_") ? safeApiKey.slice(4, 12) : "external";
1122
1155
  const reporterName = (user == null ? void 0 : user.name) || "Anonymous";
1123
1156
  const reporterEmail = (user == null ? void 0 : user.email) || "unknown@external";
1124
- return /* @__PURE__ */ jsxs3(Fragment3, { children: [
1157
+ return /* @__PURE__ */ jsxs4(Fragment3, { children: [
1125
1158
  children,
1126
1159
  /* @__PURE__ */ jsx4(
1127
1160
  FloatingButton,