glitchgrab 1.11.0 → 1.12.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 CHANGED
@@ -618,6 +618,9 @@ function ReportButton({
618
618
  position = "bottom-right",
619
619
  label = "Report Bug",
620
620
  className,
621
+ variant = "classic",
622
+ showSeverity = true,
623
+ types,
621
624
  children
622
625
  }) {
623
626
  var _a, _b;
@@ -631,8 +634,12 @@ function ReportButton({
631
634
  const fileInputRef = (0, import_react2.useRef)(null);
632
635
  const modalRef = (0, import_react2.useRef)(null);
633
636
  const glitchgrab = useGlitchgrabSafe();
637
+ const [step, setStep] = (0, import_react2.useState)(1);
638
+ const [reportType, setReportType] = (0, import_react2.useState)("BUG");
639
+ const [severity, setSeverity] = (0, import_react2.useState)("medium");
640
+ const availableTypes = types != null ? types : ["BUG", "FEATURE_REQUEST", "QUESTION", "OTHER"];
634
641
  if (!glitchgrab) return null;
635
- const { reportBug } = glitchgrab;
642
+ const { reportBug, report } = glitchgrab;
636
643
  const isDark = useIsDark();
637
644
  const t = getTheme(isDark);
638
645
  const handleFileUpload = (e) => {
@@ -667,6 +674,10 @@ function ReportButton({
667
674
  const handleOpen = async () => {
668
675
  setCapturing(true);
669
676
  setSubmitted(false);
677
+ if (variant === "stepper" && availableTypes.length === 1) {
678
+ setReportType(availableTypes[0]);
679
+ setStep(2);
680
+ }
670
681
  try {
671
682
  const { default: html2canvas } = await import("html2canvas-pro");
672
683
  const canvas = await html2canvas(document.body, {
@@ -686,34 +697,49 @@ function ReportButton({
686
697
  if (isOpen) return;
687
698
  const detail = e.detail;
688
699
  if (detail == null ? void 0 : detail.description) setDescription(detail.description);
700
+ if (detail == null ? void 0 : detail.type) {
701
+ setReportType(detail.type);
702
+ if (variant === "stepper") setStep(2);
703
+ }
689
704
  handleOpen();
690
705
  };
691
706
  window.addEventListener("glitchgrab:open-report", handler);
692
707
  return () => window.removeEventListener("glitchgrab:open-report", handler);
693
- }, [isOpen, handleOpen]);
708
+ }, [isOpen, handleOpen, variant]);
694
709
  (0, import_react2.useEffect)(() => {
695
710
  if (!isOpen) return;
696
711
  const handleEsc = (e) => {
697
712
  if (e.key === "Escape") {
698
713
  if (previewOpen) setPreviewOpen(false);
699
- else setIsOpen(false);
714
+ else handleClose();
700
715
  }
701
716
  };
702
717
  document.addEventListener("keydown", handleEsc);
703
718
  return () => document.removeEventListener("keydown", handleEsc);
704
719
  }, [isOpen, previewOpen]);
720
+ const handleClose = () => {
721
+ setIsOpen(false);
722
+ setStep(1);
723
+ setReportType("BUG");
724
+ setSeverity("medium");
725
+ };
705
726
  const handleSubmit = async () => {
706
727
  try {
707
728
  if (!description.trim() || isSubmitting) return;
708
729
  setIsSubmitting(true);
709
- const result = await reportBug(description.trim(), screenshot ? { screenshot } : void 0);
730
+ const metadata = {};
731
+ if (screenshot) metadata.screenshot = screenshot;
732
+ if (variant === "stepper" && showSeverity && reportType === "BUG") {
733
+ metadata.severity = severity;
734
+ }
735
+ const result = variant === "stepper" ? await report(reportType, description.trim(), Object.keys(metadata).length > 0 ? metadata : void 0) : await reportBug(description.trim(), Object.keys(metadata).length > 0 ? metadata : void 0);
710
736
  if (result) {
711
737
  setSubmitted(true);
712
738
  setDescription("");
713
739
  setScreenshot(null);
714
740
  setTimeout(() => {
715
741
  setSubmitted(false);
716
- setIsOpen(false);
742
+ handleClose();
717
743
  }, 2e3);
718
744
  }
719
745
  setIsSubmitting(false);
@@ -755,7 +781,7 @@ function ReportButton({
755
781
  fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
756
782
  },
757
783
  onClick: () => {
758
- if (!previewOpen) setIsOpen(false);
784
+ if (!previewOpen) handleClose();
759
785
  },
760
786
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
761
787
  "div",
@@ -777,54 +803,90 @@ function ReportButton({
777
803
  isolation: "isolate"
778
804
  },
779
805
  children: [
780
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
806
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
781
807
  "div",
782
808
  {
783
809
  style: {
784
810
  padding: "16px 16px 12px",
785
811
  borderBottom: `1px solid ${t.border}`
786
812
  },
787
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
788
- "div",
789
- {
790
- style: {
791
- display: "flex",
792
- justifyContent: "space-between",
793
- alignItems: "center"
794
- },
795
- children: [
796
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
797
- "span",
798
- {
799
- style: {
800
- fontSize: "15px",
801
- fontWeight: 600,
802
- color: t.text
803
- },
804
- children: "Report a Bug"
805
- }
806
- ),
807
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
808
- "button",
809
- {
810
- type: "button",
811
- onClick: () => setIsOpen(false),
812
- style: {
813
- background: "none",
814
- border: "none",
815
- cursor: "pointer",
816
- padding: "4px",
817
- display: "flex",
818
- alignItems: "center",
819
- justifyContent: "center"
820
- },
821
- "aria-label": "Close",
822
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", style: { display: "block" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 4L12 12M12 4L4 12", stroke: t.textMuted, strokeWidth: "2", strokeLinecap: "round" }) })
823
- }
824
- )
825
- ]
826
- }
827
- )
813
+ children: [
814
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
815
+ "div",
816
+ {
817
+ style: {
818
+ display: "flex",
819
+ justifyContent: "space-between",
820
+ alignItems: "center"
821
+ },
822
+ children: [
823
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
824
+ variant === "stepper" && step > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
825
+ "button",
826
+ {
827
+ type: "button",
828
+ onClick: () => setStep((s) => s - 1),
829
+ style: {
830
+ background: "none",
831
+ border: "none",
832
+ cursor: "pointer",
833
+ padding: "2px",
834
+ display: "flex",
835
+ alignItems: "center"
836
+ },
837
+ "aria-label": "Back",
838
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M10 3L5 8L10 13", stroke: t.textMuted, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
839
+ }
840
+ ),
841
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
842
+ "span",
843
+ {
844
+ style: {
845
+ fontSize: "15px",
846
+ fontWeight: 600,
847
+ color: t.text
848
+ },
849
+ children: variant === "stepper" ? step === 1 ? "What's on your mind?" : step === 2 ? "Tell us more" : "Review & Send" : "Report a Bug"
850
+ }
851
+ )
852
+ ] }),
853
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
854
+ "button",
855
+ {
856
+ type: "button",
857
+ onClick: handleClose,
858
+ style: {
859
+ background: "none",
860
+ border: "none",
861
+ cursor: "pointer",
862
+ padding: "4px",
863
+ display: "flex",
864
+ alignItems: "center",
865
+ justifyContent: "center"
866
+ },
867
+ "aria-label": "Close",
868
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", style: { display: "block" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 4L12 12M12 4L4 12", stroke: t.textMuted, strokeWidth: "2", strokeLinecap: "round" }) })
869
+ }
870
+ )
871
+ ]
872
+ }
873
+ ),
874
+ variant === "stepper" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0", marginTop: "12px" }, children: [1, 2, 3].map((s, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center" }, children: [
875
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
876
+ width: "8px",
877
+ height: "8px",
878
+ borderRadius: "50%",
879
+ backgroundColor: s <= step ? t.accent : t.inputBorder,
880
+ transition: "background-color 0.2s ease"
881
+ } }),
882
+ i < 2 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
883
+ width: "40px",
884
+ height: "2px",
885
+ backgroundColor: s < step ? t.accent : t.inputBorder,
886
+ transition: "background-color 0.2s ease"
887
+ } })
888
+ ] }, s)) })
889
+ ]
828
890
  }
829
891
  ),
830
892
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "16px" }, children: submitted ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
@@ -837,201 +899,474 @@ function ReportButton({
837
899
  fontSize: "14px",
838
900
  fontWeight: 500
839
901
  },
840
- children: "Bug report sent. Thank you!"
902
+ children: variant === "stepper" ? `${getTypeLabel(reportType)} sent. Thank you!` : "Bug report sent. Thank you!"
841
903
  }
842
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
843
- screenshot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "10px", position: "relative" }, children: [
844
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
845
- "img",
846
- {
847
- src: screenshot,
848
- alt: "Page screenshot",
849
- onClick: () => setPreviewOpen(true),
850
- style: {
851
- width: "100%",
852
- borderRadius: "6px",
853
- border: `1px solid ${t.border}`,
854
- maxHeight: "120px",
855
- objectFit: "cover",
856
- objectPosition: "top",
857
- cursor: "pointer"
858
- }
859
- }
860
- ),
861
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
904
+ ) : variant === "stepper" ? (
905
+ /* ─── Stepper Flow ─── */
906
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
907
+ step === 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "8px" }, children: availableTypes.map((type) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
862
908
  "button",
863
909
  {
864
910
  type: "button",
865
- onClick: () => setScreenshot(null),
911
+ onClick: () => {
912
+ setReportType(type);
913
+ setStep(2);
914
+ },
866
915
  style: {
867
- position: "absolute",
868
- top: "4px",
869
- right: "4px",
870
- background: "rgba(0,0,0,0.6)",
871
- border: "none",
872
- borderRadius: "50%",
873
- width: "20px",
874
- height: "20px",
875
- cursor: "pointer",
876
916
  display: "flex",
917
+ flexDirection: "column",
877
918
  alignItems: "center",
878
- justifyContent: "center"
919
+ gap: "8px",
920
+ padding: "16px 8px",
921
+ borderRadius: "8px",
922
+ border: `1px solid ${t.inputBorder}`,
923
+ background: t.inputBg,
924
+ cursor: "pointer",
925
+ color: t.text,
926
+ fontFamily: "inherit",
927
+ transition: "border-color 0.15s ease"
879
928
  },
880
- "aria-label": "Remove screenshot",
881
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1L9 9M9 1L1 9", stroke: "#fff", strokeWidth: "1.5", strokeLinecap: "round" }) })
882
- }
883
- ),
884
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
885
- "div",
886
- {
887
- style: {
888
- position: "absolute",
889
- bottom: "4px",
890
- left: "6px",
891
- right: "6px",
892
- display: "flex",
893
- justifyContent: "space-between",
894
- alignItems: "center"
929
+ onMouseEnter: (e) => {
930
+ e.currentTarget.style.borderColor = t.accent;
931
+ },
932
+ onMouseLeave: (e) => {
933
+ e.currentTarget.style.borderColor = t.inputBorder;
895
934
  },
896
935
  children: [
897
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
898
- "span",
899
- {
900
- style: {
901
- background: "rgba(0,0,0,0.6)",
902
- color: "#fff",
903
- fontSize: "10px",
904
- padding: "2px 6px",
905
- borderRadius: "4px"
906
- },
907
- children: [
908
- "Screenshot (",
909
- Math.round(screenshot.length * 0.75 / 1024),
910
- "KB) \u2014 click to preview"
911
- ]
936
+ getTypeIcon(type, t.accent),
937
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "13px", fontWeight: 600 }, children: getTypeLabel(type) }),
938
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "11px", color: t.textMuted, lineHeight: "1.3" }, children: getTypeSubtitle(type) })
939
+ ]
940
+ },
941
+ type
942
+ )) }),
943
+ step === 2 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
944
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
945
+ "textarea",
946
+ {
947
+ value: description,
948
+ onChange: (e) => setDescription(e.target.value),
949
+ placeholder: getPlaceholder(reportType),
950
+ style: {
951
+ width: "100%",
952
+ minHeight: "100px",
953
+ padding: "10px 12px",
954
+ borderRadius: "8px",
955
+ border: `1px solid ${t.inputBorder}`,
956
+ fontSize: "14px",
957
+ fontFamily: "inherit",
958
+ resize: "vertical",
959
+ outline: "none",
960
+ boxSizing: "border-box",
961
+ color: t.text,
962
+ backgroundColor: t.inputBg
963
+ },
964
+ onFocus: (e) => {
965
+ e.target.style.borderColor = t.accent;
966
+ },
967
+ onBlur: (e) => {
968
+ e.target.style.borderColor = t.inputBorder;
969
+ },
970
+ autoFocus: true
971
+ }
972
+ ),
973
+ showSeverity && reportType === "BUG" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginTop: "10px" }, children: [
974
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "12px", color: t.textMuted, marginBottom: "6px", display: "block" }, children: "Severity" }),
975
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: "6px" }, children: ["low", "medium", "high"].map((s) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
976
+ "button",
977
+ {
978
+ type: "button",
979
+ onClick: () => setSeverity(s),
980
+ style: {
981
+ flex: 1,
982
+ padding: "6px 0",
983
+ borderRadius: "6px",
984
+ border: `1px solid ${severity === s ? t.accent : t.inputBorder}`,
985
+ background: severity === s ? t.accent : "transparent",
986
+ color: severity === s ? t.accentText : t.text,
987
+ fontSize: "12px",
988
+ fontWeight: 600,
989
+ cursor: "pointer",
990
+ fontFamily: "inherit",
991
+ textTransform: "capitalize",
992
+ transition: "all 0.15s ease"
993
+ },
994
+ children: s
995
+ },
996
+ s
997
+ )) })
998
+ ] }),
999
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1000
+ "button",
1001
+ {
1002
+ type: "button",
1003
+ onClick: () => setStep(3),
1004
+ disabled: !description.trim(),
1005
+ style: {
1006
+ marginTop: "12px",
1007
+ width: "100%",
1008
+ padding: "10px",
1009
+ borderRadius: "8px",
1010
+ border: "none",
1011
+ backgroundColor: !description.trim() ? t.bgSecondary : t.accent,
1012
+ color: !description.trim() ? t.textMuted : t.accentText,
1013
+ fontSize: "14px",
1014
+ fontWeight: 600,
1015
+ cursor: !description.trim() ? "not-allowed" : "pointer",
1016
+ fontFamily: "inherit",
1017
+ transition: "background-color 0.15s ease"
1018
+ },
1019
+ children: "Next"
1020
+ }
1021
+ )
1022
+ ] }),
1023
+ step === 3 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1024
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap", marginBottom: "12px" }, children: [
1025
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: {
1026
+ display: "inline-flex",
1027
+ alignItems: "center",
1028
+ gap: "4px",
1029
+ padding: "4px 10px",
1030
+ borderRadius: "12px",
1031
+ fontSize: "12px",
1032
+ fontWeight: 600,
1033
+ backgroundColor: t.bgSecondary,
1034
+ color: t.text,
1035
+ border: `1px solid ${t.border}`
1036
+ }, children: [
1037
+ getTypeIcon(reportType, t.accent, 12),
1038
+ getTypeLabel(reportType)
1039
+ ] }),
1040
+ showSeverity && reportType === "BUG" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: {
1041
+ display: "inline-flex",
1042
+ alignItems: "center",
1043
+ padding: "4px 10px",
1044
+ borderRadius: "12px",
1045
+ fontSize: "12px",
1046
+ fontWeight: 600,
1047
+ backgroundColor: severity === "high" ? "#fef2f2" : severity === "medium" ? "#fffbeb" : "#f0fdf4",
1048
+ color: severity === "high" ? "#dc2626" : severity === "medium" ? "#d97706" : "#16a34a",
1049
+ border: `1px solid ${severity === "high" ? "#fecaca" : severity === "medium" ? "#fde68a" : "#bbf7d0"}`,
1050
+ textTransform: "capitalize"
1051
+ }, children: severity })
1052
+ ] }),
1053
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
1054
+ padding: "10px 12px",
1055
+ borderRadius: "8px",
1056
+ border: `1px solid ${t.inputBorder}`,
1057
+ backgroundColor: t.inputBg,
1058
+ fontSize: "13px",
1059
+ color: t.text,
1060
+ marginBottom: "10px",
1061
+ maxHeight: "80px",
1062
+ overflow: "hidden",
1063
+ lineHeight: "1.4"
1064
+ }, children: description.length > 200 ? description.slice(0, 200) + "..." : description }),
1065
+ screenshot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "10px", position: "relative" }, children: [
1066
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1067
+ "img",
1068
+ {
1069
+ src: screenshot,
1070
+ alt: "Page screenshot",
1071
+ onClick: () => setPreviewOpen(true),
1072
+ style: {
1073
+ width: "100%",
1074
+ borderRadius: "6px",
1075
+ border: `1px solid ${t.border}`,
1076
+ maxHeight: "80px",
1077
+ objectFit: "cover",
1078
+ objectPosition: "top",
1079
+ cursor: "pointer"
912
1080
  }
913
- ),
914
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "4px" }, children: [
915
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
916
- "button",
1081
+ }
1082
+ ),
1083
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1084
+ "button",
1085
+ {
1086
+ type: "button",
1087
+ onClick: () => setScreenshot(null),
1088
+ style: {
1089
+ position: "absolute",
1090
+ top: "4px",
1091
+ right: "4px",
1092
+ background: "rgba(0,0,0,0.6)",
1093
+ border: "none",
1094
+ borderRadius: "50%",
1095
+ width: "20px",
1096
+ height: "20px",
1097
+ cursor: "pointer",
1098
+ display: "flex",
1099
+ alignItems: "center",
1100
+ justifyContent: "center"
1101
+ },
1102
+ "aria-label": "Remove screenshot",
1103
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1L9 9M9 1L1 9", stroke: "#fff", strokeWidth: "1.5", strokeLinecap: "round" }) })
1104
+ }
1105
+ )
1106
+ ] }),
1107
+ !screenshot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "6px", marginBottom: "10px" }, children: [
1108
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1109
+ "button",
1110
+ {
1111
+ type: "button",
1112
+ onClick: () => {
1113
+ var _a2;
1114
+ return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
1115
+ },
1116
+ style: {
1117
+ flex: 1,
1118
+ padding: "8px",
1119
+ borderRadius: "6px",
1120
+ border: `1px dashed ${t.inputBorder}`,
1121
+ textAlign: "center",
1122
+ fontSize: "11px",
1123
+ color: t.textMuted,
1124
+ background: "none",
1125
+ cursor: "pointer"
1126
+ },
1127
+ children: "Upload screenshot"
1128
+ }
1129
+ ),
1130
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1131
+ "button",
1132
+ {
1133
+ type: "button",
1134
+ onClick: retakeScreenshot,
1135
+ style: {
1136
+ flex: 1,
1137
+ padding: "8px",
1138
+ borderRadius: "6px",
1139
+ border: `1px dashed ${t.inputBorder}`,
1140
+ textAlign: "center",
1141
+ fontSize: "11px",
1142
+ color: t.textMuted,
1143
+ background: "none",
1144
+ cursor: "pointer"
1145
+ },
1146
+ children: "Retake screenshot"
1147
+ }
1148
+ )
1149
+ ] }),
1150
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1151
+ "button",
1152
+ {
1153
+ type: "button",
1154
+ onClick: handleSubmit,
1155
+ disabled: isSubmitting,
1156
+ style: {
1157
+ width: "100%",
1158
+ padding: "10px",
1159
+ borderRadius: "8px",
1160
+ border: "none",
1161
+ backgroundColor: isSubmitting ? t.bgSecondary : t.accent,
1162
+ color: isSubmitting ? t.textMuted : t.accentText,
1163
+ fontSize: "14px",
1164
+ fontWeight: 600,
1165
+ cursor: isSubmitting ? "not-allowed" : "pointer",
1166
+ fontFamily: "inherit",
1167
+ transition: "background-color 0.15s ease"
1168
+ },
1169
+ children: isSubmitting ? "Sending..." : "Send Report"
1170
+ }
1171
+ )
1172
+ ] })
1173
+ ] })
1174
+ ) : (
1175
+ /* ─── Classic Flow ─── */
1176
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1177
+ screenshot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "10px", position: "relative" }, children: [
1178
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1179
+ "img",
1180
+ {
1181
+ src: screenshot,
1182
+ alt: "Page screenshot",
1183
+ onClick: () => setPreviewOpen(true),
1184
+ style: {
1185
+ width: "100%",
1186
+ borderRadius: "6px",
1187
+ border: `1px solid ${t.border}`,
1188
+ maxHeight: "120px",
1189
+ objectFit: "cover",
1190
+ objectPosition: "top",
1191
+ cursor: "pointer"
1192
+ }
1193
+ }
1194
+ ),
1195
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1196
+ "button",
1197
+ {
1198
+ type: "button",
1199
+ onClick: () => setScreenshot(null),
1200
+ style: {
1201
+ position: "absolute",
1202
+ top: "4px",
1203
+ right: "4px",
1204
+ background: "rgba(0,0,0,0.6)",
1205
+ border: "none",
1206
+ borderRadius: "50%",
1207
+ width: "20px",
1208
+ height: "20px",
1209
+ cursor: "pointer",
1210
+ display: "flex",
1211
+ alignItems: "center",
1212
+ justifyContent: "center"
1213
+ },
1214
+ "aria-label": "Remove screenshot",
1215
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M1 1L9 9M9 1L1 9", stroke: "#fff", strokeWidth: "1.5", strokeLinecap: "round" }) })
1216
+ }
1217
+ ),
1218
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1219
+ "div",
1220
+ {
1221
+ style: {
1222
+ position: "absolute",
1223
+ bottom: "4px",
1224
+ left: "6px",
1225
+ right: "6px",
1226
+ display: "flex",
1227
+ justifyContent: "space-between",
1228
+ alignItems: "center"
1229
+ },
1230
+ children: [
1231
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1232
+ "span",
917
1233
  {
918
- type: "button",
919
- onClick: () => {
920
- var _a2;
921
- return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
922
- },
923
1234
  style: {
924
- background: t.accent,
925
- color: t.accentText,
1235
+ background: "rgba(0,0,0,0.6)",
1236
+ color: "#fff",
926
1237
  fontSize: "10px",
927
- padding: "3px 8px",
928
- borderRadius: "4px",
929
- border: "none",
930
- cursor: "pointer",
931
- fontWeight: 600
1238
+ padding: "2px 6px",
1239
+ borderRadius: "4px"
932
1240
  },
933
- children: "Upload"
1241
+ children: [
1242
+ "Screenshot (",
1243
+ Math.round(screenshot.length * 0.75 / 1024),
1244
+ "KB) \u2014 click to preview"
1245
+ ]
934
1246
  }
935
1247
  ),
936
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
937
- "button",
938
- {
939
- type: "button",
940
- onClick: retakeScreenshot,
941
- style: {
942
- background: t.accent,
943
- color: t.accentText,
944
- fontSize: "10px",
945
- padding: "3px 8px",
946
- borderRadius: "4px",
947
- border: "none",
948
- cursor: "pointer",
949
- fontWeight: 600
950
- },
951
- children: "Retake"
952
- }
953
- )
954
- ] })
955
- ]
1248
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "4px" }, children: [
1249
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1250
+ "button",
1251
+ {
1252
+ type: "button",
1253
+ onClick: () => {
1254
+ var _a2;
1255
+ return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
1256
+ },
1257
+ style: {
1258
+ background: t.accent,
1259
+ color: t.accentText,
1260
+ fontSize: "10px",
1261
+ padding: "3px 8px",
1262
+ borderRadius: "4px",
1263
+ border: "none",
1264
+ cursor: "pointer",
1265
+ fontWeight: 600
1266
+ },
1267
+ children: "Upload"
1268
+ }
1269
+ ),
1270
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1271
+ "button",
1272
+ {
1273
+ type: "button",
1274
+ onClick: retakeScreenshot,
1275
+ style: {
1276
+ background: t.accent,
1277
+ color: t.accentText,
1278
+ fontSize: "10px",
1279
+ padding: "3px 8px",
1280
+ borderRadius: "4px",
1281
+ border: "none",
1282
+ cursor: "pointer",
1283
+ fontWeight: 600
1284
+ },
1285
+ children: "Retake"
1286
+ }
1287
+ )
1288
+ ] })
1289
+ ]
1290
+ }
1291
+ )
1292
+ ] }),
1293
+ !screenshot && !submitted && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1294
+ "button",
1295
+ {
1296
+ type: "button",
1297
+ onClick: () => {
1298
+ var _a2;
1299
+ return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
1300
+ },
1301
+ style: {
1302
+ marginBottom: "10px",
1303
+ padding: "10px",
1304
+ borderRadius: "6px",
1305
+ border: `1px dashed ${t.inputBorder}`,
1306
+ textAlign: "center",
1307
+ fontSize: "11px",
1308
+ color: t.textMuted,
1309
+ width: "100%",
1310
+ background: "none",
1311
+ cursor: "pointer"
1312
+ },
1313
+ children: "Click to upload a screenshot"
1314
+ }
1315
+ ),
1316
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1317
+ "textarea",
1318
+ {
1319
+ value: description,
1320
+ onChange: (e) => setDescription(e.target.value),
1321
+ placeholder: "Describe what went wrong...",
1322
+ style: {
1323
+ width: "100%",
1324
+ minHeight: "100px",
1325
+ padding: "10px 12px",
1326
+ borderRadius: "8px",
1327
+ border: `1px solid ${t.inputBorder}`,
1328
+ fontSize: "14px",
1329
+ fontFamily: "inherit",
1330
+ resize: "vertical",
1331
+ outline: "none",
1332
+ boxSizing: "border-box",
1333
+ color: t.text,
1334
+ backgroundColor: t.inputBg
1335
+ },
1336
+ onFocus: (e) => {
1337
+ e.target.style.borderColor = t.accent;
1338
+ },
1339
+ onBlur: (e) => {
1340
+ e.target.style.borderColor = t.inputBorder;
1341
+ },
1342
+ autoFocus: true
1343
+ }
1344
+ ),
1345
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1346
+ "button",
1347
+ {
1348
+ type: "button",
1349
+ onClick: handleSubmit,
1350
+ disabled: !description.trim() || isSubmitting,
1351
+ style: {
1352
+ marginTop: "12px",
1353
+ width: "100%",
1354
+ padding: "10px",
1355
+ borderRadius: "8px",
1356
+ border: "none",
1357
+ backgroundColor: !description.trim() || isSubmitting ? t.bgSecondary : t.accent,
1358
+ color: !description.trim() || isSubmitting ? t.textMuted : t.accentText,
1359
+ fontSize: "14px",
1360
+ fontWeight: 600,
1361
+ cursor: !description.trim() || isSubmitting ? "not-allowed" : "pointer",
1362
+ fontFamily: "inherit",
1363
+ transition: "background-color 0.15s ease"
1364
+ },
1365
+ children: isSubmitting ? "Sending..." : "Send Report"
956
1366
  }
957
1367
  )
958
- ] }),
959
- !screenshot && !submitted && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
960
- "button",
961
- {
962
- type: "button",
963
- onClick: () => {
964
- var _a2;
965
- return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
966
- },
967
- style: {
968
- marginBottom: "10px",
969
- padding: "10px",
970
- borderRadius: "6px",
971
- border: `1px dashed ${t.inputBorder}`,
972
- textAlign: "center",
973
- fontSize: "11px",
974
- color: t.textMuted,
975
- width: "100%",
976
- background: "none",
977
- cursor: "pointer"
978
- },
979
- children: "Click to upload a screenshot"
980
- }
981
- ),
982
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
983
- "textarea",
984
- {
985
- value: description,
986
- onChange: (e) => setDescription(e.target.value),
987
- placeholder: "Describe what went wrong...",
988
- style: {
989
- width: "100%",
990
- minHeight: "100px",
991
- padding: "10px 12px",
992
- borderRadius: "8px",
993
- border: `1px solid ${t.inputBorder}`,
994
- fontSize: "14px",
995
- fontFamily: "inherit",
996
- resize: "vertical",
997
- outline: "none",
998
- boxSizing: "border-box",
999
- color: t.text,
1000
- backgroundColor: t.inputBg
1001
- },
1002
- onFocus: (e) => {
1003
- e.target.style.borderColor = t.accent;
1004
- },
1005
- onBlur: (e) => {
1006
- e.target.style.borderColor = t.inputBorder;
1007
- },
1008
- autoFocus: true
1009
- }
1010
- ),
1011
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1012
- "button",
1013
- {
1014
- type: "button",
1015
- onClick: handleSubmit,
1016
- disabled: !description.trim() || isSubmitting,
1017
- style: {
1018
- marginTop: "12px",
1019
- width: "100%",
1020
- padding: "10px",
1021
- borderRadius: "8px",
1022
- border: "none",
1023
- backgroundColor: !description.trim() || isSubmitting ? t.bgSecondary : t.accent,
1024
- color: !description.trim() || isSubmitting ? t.textMuted : t.accentText,
1025
- fontSize: "14px",
1026
- fontWeight: 600,
1027
- cursor: !description.trim() || isSubmitting ? "not-allowed" : "pointer",
1028
- fontFamily: "inherit",
1029
- transition: "background-color 0.15s ease"
1030
- },
1031
- children: isSubmitting ? "Sending..." : "Send Report"
1032
- }
1033
- )
1034
- ] }) }),
1368
+ ] })
1369
+ ) }),
1035
1370
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1036
1371
  "div",
1037
1372
  {
@@ -1115,6 +1450,58 @@ function ReportButton({
1115
1450
  )
1116
1451
  ] });
1117
1452
  }
1453
+ function getTypeLabel(type) {
1454
+ switch (type) {
1455
+ case "BUG":
1456
+ return "Bug Report";
1457
+ case "FEATURE_REQUEST":
1458
+ return "Feature Request";
1459
+ case "QUESTION":
1460
+ return "Question";
1461
+ case "OTHER":
1462
+ return "Other";
1463
+ }
1464
+ }
1465
+ function getTypeSubtitle(type) {
1466
+ switch (type) {
1467
+ case "BUG":
1468
+ return "Something isn't working";
1469
+ case "FEATURE_REQUEST":
1470
+ return "Suggest an improvement";
1471
+ case "QUESTION":
1472
+ return "Ask a question";
1473
+ case "OTHER":
1474
+ return "General feedback";
1475
+ }
1476
+ }
1477
+ function getPlaceholder(type) {
1478
+ switch (type) {
1479
+ case "BUG":
1480
+ return "What went wrong?";
1481
+ case "FEATURE_REQUEST":
1482
+ return "Describe the feature you'd like...";
1483
+ case "QUESTION":
1484
+ return "What would you like to know?";
1485
+ case "OTHER":
1486
+ return "Tell us what's on your mind...";
1487
+ }
1488
+ }
1489
+ function getTypeIcon(type, color, size = 24) {
1490
+ const props = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", style: { flexShrink: 0 } };
1491
+ switch (type) {
1492
+ case "BUG":
1493
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 2L6.5 3.5M16 2L17.5 3.5M3 9H7M17 9H21M12 2a5 5 0 015 5v4a5 5 0 01-10 0V7a5 5 0 015-5zM7 16l-2 3M17 16l2 3", stroke: color, strokeWidth: "1.5", strokeLinecap: "round" }) });
1494
+ case "FEATURE_REQUEST":
1495
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2z", stroke: color, strokeWidth: "1.5", strokeLinejoin: "round" }) });
1496
+ case "QUESTION":
1497
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...props, children: [
1498
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "10", stroke: color, strokeWidth: "1.5" }),
1499
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3M12 17h.01", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1500
+ ] });
1501
+ case "OTHER":
1502
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z", stroke: color, strokeWidth: "1.5", strokeLinejoin: "round" }) });
1503
+ }
1504
+ }
1118
1505
  function DefaultTrigger({
1119
1506
  onClick,
1120
1507
  capturing,