glitchgrab 1.26.0 → 1.27.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.mjs CHANGED
@@ -4,8 +4,8 @@
4
4
  import {
5
5
  createContext,
6
6
  useContext,
7
- useRef as useRef2,
8
- useEffect as useEffect2,
7
+ useRef as useRef3,
8
+ useEffect as useEffect3,
9
9
  useCallback
10
10
  } from "react";
11
11
 
@@ -453,12 +453,293 @@ var GlitchgrabErrorBoundary = class extends React.Component {
453
453
 
454
454
  // src/report-dialog.tsx
455
455
  import {
456
- useState,
457
- useRef,
458
- useEffect
456
+ useState as useState2,
457
+ useRef as useRef2,
458
+ useEffect as useEffect2
459
459
  } from "react";
460
460
  import { createPortal } from "react-dom";
461
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
461
+
462
+ // src/annotation-canvas.tsx
463
+ import { useEffect, useRef, useState } from "react";
464
+ import { jsx, jsxs } from "react/jsx-runtime";
465
+ var PALETTE = ["#ef4444", "#f59e0b", "#22c55e", "#3b82f6", "#a855f7", "#ffffff"];
466
+ function drawStroke(ctx, s) {
467
+ ctx.strokeStyle = s.color;
468
+ ctx.lineWidth = s.width;
469
+ ctx.lineCap = "round";
470
+ ctx.lineJoin = "round";
471
+ if (s.type === "freehand") {
472
+ if (s.points.length < 2) return;
473
+ ctx.beginPath();
474
+ ctx.moveTo(s.points[0].x, s.points[0].y);
475
+ for (let i = 1; i < s.points.length; i++) ctx.lineTo(s.points[i].x, s.points[i].y);
476
+ ctx.stroke();
477
+ } else {
478
+ ctx.beginPath();
479
+ ctx.arc(s.cx, s.cy, s.r, 0, Math.PI * 2);
480
+ ctx.stroke();
481
+ }
482
+ }
483
+ function AnnotationCanvas({ imageSrc, onSave, onCancel }) {
484
+ const canvasRef = useRef(null);
485
+ const imgRef = useRef(null);
486
+ const [ready, setReady] = useState(false);
487
+ const [tool, setTool] = useState("pen");
488
+ const [color, setColor] = useState(PALETTE[0]);
489
+ const [strokeWidth, setStrokeWidth] = useState(4);
490
+ const [strokes, setStrokes] = useState([]);
491
+ const [currentStroke, setCurrentStroke] = useState(null);
492
+ useEffect(() => {
493
+ const img = new Image();
494
+ img.onload = () => {
495
+ imgRef.current = img;
496
+ const canvas = canvasRef.current;
497
+ if (canvas) {
498
+ canvas.width = img.naturalWidth;
499
+ canvas.height = img.naturalHeight;
500
+ }
501
+ setReady(true);
502
+ };
503
+ img.src = imageSrc;
504
+ }, [imageSrc]);
505
+ useEffect(() => {
506
+ if (!ready) return;
507
+ const canvas = canvasRef.current;
508
+ const img = imgRef.current;
509
+ if (!canvas || !img) return;
510
+ const ctx = canvas.getContext("2d");
511
+ if (!ctx) return;
512
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
513
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
514
+ for (const s of strokes) drawStroke(ctx, s);
515
+ if (currentStroke) drawStroke(ctx, currentStroke);
516
+ }, [ready, strokes, currentStroke]);
517
+ const getPos = (e) => {
518
+ const canvas = e.currentTarget;
519
+ const rect = canvas.getBoundingClientRect();
520
+ return {
521
+ x: (e.clientX - rect.left) * canvas.width / rect.width,
522
+ y: (e.clientY - rect.top) * canvas.height / rect.height
523
+ };
524
+ };
525
+ const handlePointerDown = (e) => {
526
+ e.currentTarget.setPointerCapture(e.pointerId);
527
+ const { x, y } = getPos(e);
528
+ setCurrentStroke(
529
+ tool === "pen" ? { type: "freehand", color, width: strokeWidth, points: [{ x, y }] } : { type: "circle", color, width: strokeWidth, cx: x, cy: y, r: 0 }
530
+ );
531
+ };
532
+ const handlePointerMove = (e) => {
533
+ if (!currentStroke) return;
534
+ const { x, y } = getPos(e);
535
+ setCurrentStroke((prev) => {
536
+ if (!prev) return prev;
537
+ if (prev.type === "freehand") return { ...prev, points: [...prev.points, { x, y }] };
538
+ return { ...prev, r: Math.hypot(x - prev.cx, y - prev.cy) };
539
+ });
540
+ };
541
+ const handlePointerUp = () => {
542
+ setCurrentStroke((prev) => {
543
+ if (prev) setStrokes((s) => [...s, prev]);
544
+ return null;
545
+ });
546
+ };
547
+ const handleSave = () => {
548
+ const canvas = canvasRef.current;
549
+ if (!canvas) return;
550
+ onSave(canvas.toDataURL("image/jpeg", 0.85));
551
+ };
552
+ const iconBtn = (active = false) => ({
553
+ width: "30px",
554
+ height: "30px",
555
+ display: "flex",
556
+ alignItems: "center",
557
+ justifyContent: "center",
558
+ borderRadius: "6px",
559
+ border: `1.5px solid ${active ? "#22d3ee" : "rgba(255,255,255,0.15)"}`,
560
+ background: active ? "rgba(34,211,238,0.15)" : "transparent",
561
+ color: "#fff",
562
+ cursor: "pointer",
563
+ padding: 0
564
+ });
565
+ return /* @__PURE__ */ jsxs(
566
+ "div",
567
+ {
568
+ style: {
569
+ position: "fixed",
570
+ inset: 0,
571
+ zIndex: 2147483647,
572
+ backgroundColor: "rgba(0,0,0,0.9)",
573
+ display: "flex",
574
+ flexDirection: "column",
575
+ alignItems: "center",
576
+ justifyContent: "center",
577
+ padding: "16px"
578
+ },
579
+ onClick: (e) => {
580
+ e.stopPropagation();
581
+ if (e.target === e.currentTarget) onCancel();
582
+ },
583
+ onPointerDown: (e) => e.stopPropagation(),
584
+ children: [
585
+ /* @__PURE__ */ jsx(
586
+ "canvas",
587
+ {
588
+ ref: canvasRef,
589
+ onPointerDown: handlePointerDown,
590
+ onPointerMove: handlePointerMove,
591
+ onPointerUp: handlePointerUp,
592
+ style: {
593
+ maxWidth: "100%",
594
+ maxHeight: "calc(100vh - 140px)",
595
+ borderRadius: "8px",
596
+ touchAction: "none",
597
+ cursor: "crosshair",
598
+ display: "block"
599
+ }
600
+ }
601
+ ),
602
+ /* @__PURE__ */ jsxs(
603
+ "div",
604
+ {
605
+ style: {
606
+ marginTop: "14px",
607
+ display: "flex",
608
+ alignItems: "center",
609
+ gap: "8px",
610
+ flexWrap: "wrap",
611
+ justifyContent: "center",
612
+ maxWidth: "100%"
613
+ },
614
+ children: [
615
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setTool("pen"), style: iconBtn(tool === "pen"), title: "Freehand", "aria-label": "Freehand tool", children: /* @__PURE__ */ jsx("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
616
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setTool("circle"), style: iconBtn(tool === "circle"), title: "Circle", "aria-label": "Circle tool", children: /* @__PURE__ */ jsx("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "8", stroke: "currentColor", strokeWidth: "1.8" }) }) }),
617
+ /* @__PURE__ */ jsx("div", { style: { width: "1px", height: "20px", background: "rgba(255,255,255,0.15)" } }),
618
+ PALETTE.map((c) => /* @__PURE__ */ jsx(
619
+ "button",
620
+ {
621
+ type: "button",
622
+ onClick: () => setColor(c),
623
+ "aria-label": `Color ${c}`,
624
+ style: {
625
+ width: "22px",
626
+ height: "22px",
627
+ borderRadius: "50%",
628
+ background: c,
629
+ border: color === c ? "2px solid #22d3ee" : "2px solid rgba(255,255,255,0.3)",
630
+ cursor: "pointer",
631
+ padding: 0
632
+ }
633
+ },
634
+ c
635
+ )),
636
+ /* @__PURE__ */ jsx(
637
+ "input",
638
+ {
639
+ type: "color",
640
+ value: color,
641
+ onChange: (e) => setColor(e.target.value),
642
+ title: "Custom color",
643
+ "aria-label": "Custom color",
644
+ style: {
645
+ width: "22px",
646
+ height: "22px",
647
+ padding: 0,
648
+ border: "none",
649
+ background: "none",
650
+ cursor: "pointer"
651
+ }
652
+ }
653
+ ),
654
+ /* @__PURE__ */ jsx("div", { style: { width: "1px", height: "20px", background: "rgba(255,255,255,0.15)" } }),
655
+ /* @__PURE__ */ jsx(
656
+ "input",
657
+ {
658
+ type: "range",
659
+ min: 2,
660
+ max: 12,
661
+ value: strokeWidth,
662
+ onChange: (e) => setStrokeWidth(Number(e.target.value)),
663
+ title: "Stroke width",
664
+ "aria-label": "Stroke width",
665
+ style: { width: "70px" }
666
+ }
667
+ ),
668
+ /* @__PURE__ */ jsx("div", { style: { width: "1px", height: "20px", background: "rgba(255,255,255,0.15)" } }),
669
+ /* @__PURE__ */ jsx(
670
+ "button",
671
+ {
672
+ type: "button",
673
+ onClick: () => setStrokes((s) => s.slice(0, -1)),
674
+ disabled: strokes.length === 0,
675
+ style: { ...iconBtn(), opacity: strokes.length === 0 ? 0.35 : 1 },
676
+ title: "Undo",
677
+ "aria-label": "Undo",
678
+ children: /* @__PURE__ */ jsx("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M9 14L4 9l5-5M4 9h10a6 6 0 010 12h-2", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) })
679
+ }
680
+ ),
681
+ /* @__PURE__ */ jsx(
682
+ "button",
683
+ {
684
+ type: "button",
685
+ onClick: () => setStrokes([]),
686
+ disabled: strokes.length === 0,
687
+ style: { ...iconBtn(), opacity: strokes.length === 0 ? 0.35 : 1 },
688
+ title: "Clear all",
689
+ "aria-label": "Clear all",
690
+ children: /* @__PURE__ */ jsx("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M3 6h18M8 6V4a1 1 0 011-1h6a1 1 0 011 1v2m2 0v14a1 1 0 01-1 1H7a1 1 0 01-1-1V6h12z", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) })
691
+ }
692
+ )
693
+ ]
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsxs("div", { style: { marginTop: "12px", display: "flex", gap: "8px" }, children: [
697
+ /* @__PURE__ */ jsx(
698
+ "button",
699
+ {
700
+ type: "button",
701
+ onClick: onCancel,
702
+ style: {
703
+ padding: "8px 16px",
704
+ borderRadius: "8px",
705
+ border: "1.5px solid rgba(255,255,255,0.2)",
706
+ background: "transparent",
707
+ color: "#fff",
708
+ fontSize: "13px",
709
+ fontWeight: 600,
710
+ cursor: "pointer",
711
+ fontFamily: "inherit"
712
+ },
713
+ children: "Cancel"
714
+ }
715
+ ),
716
+ /* @__PURE__ */ jsx(
717
+ "button",
718
+ {
719
+ type: "button",
720
+ onClick: handleSave,
721
+ style: {
722
+ padding: "8px 16px",
723
+ borderRadius: "8px",
724
+ border: "none",
725
+ background: "#22d3ee",
726
+ color: "#09090b",
727
+ fontSize: "13px",
728
+ fontWeight: 600,
729
+ cursor: "pointer",
730
+ fontFamily: "inherit"
731
+ },
732
+ children: "Save annotation"
733
+ }
734
+ )
735
+ ] })
736
+ ]
737
+ }
738
+ );
739
+ }
740
+
741
+ // src/report-dialog.tsx
742
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
462
743
  function useIsDark() {
463
744
  if (typeof window === "undefined") return true;
464
745
  try {
@@ -647,39 +928,40 @@ function ReportDialog({
647
928
  types,
648
929
  showSeverity = true
649
930
  }) {
650
- const [isEnhancing, setIsEnhancing] = useState(false);
651
- const [isEnhanced, setIsEnhanced] = useState(false);
652
- const [originalDescription, setOriginalDescription] = useState(
931
+ const [isEnhancing, setIsEnhancing] = useState2(false);
932
+ const [isEnhanced, setIsEnhanced] = useState2(false);
933
+ const [originalDescription, setOriginalDescription] = useState2(
653
934
  null
654
935
  );
655
- const [isListening, setIsListening] = useState(false);
656
- const [isTranscribing, setIsTranscribing] = useState(false);
657
- const [voiceError, setVoiceError] = useState(null);
658
- const [screenshotDragOver, setScreenshotDragOver] = useState(false);
659
- const [mounted, setMounted] = useState(false);
660
- useEffect(() => {
936
+ const [isListening, setIsListening] = useState2(false);
937
+ const [isTranscribing, setIsTranscribing] = useState2(false);
938
+ const [voiceError, setVoiceError] = useState2(null);
939
+ const [screenshotDragOver, setScreenshotDragOver] = useState2(false);
940
+ const [mounted, setMounted] = useState2(false);
941
+ useEffect2(() => {
661
942
  setMounted(true);
662
943
  }, []);
663
- const [isOpen, setIsOpen] = useState(false);
664
- const [description, setDescription] = useState("");
665
- const [isSubmitting, setIsSubmitting] = useState(false);
666
- const [submitted, setSubmitted] = useState(false);
667
- const [screenshots, setScreenshots] = useState([]);
668
- const [previewIndex, setPreviewIndex] = useState(null);
669
- const fileInputRef = useRef(null);
670
- const modalRef = useRef(null);
671
- const previewImgRef = useRef(null);
672
- const textareaRef = useRef(null);
673
- const recognitionRef = useRef(null);
674
- const voiceBaseRef = useRef("");
675
- const usingWebSpeechRef = useRef(false);
676
- const textBeforeVoiceRef = useRef("");
677
- const mediaRecorderRef = useRef(null);
678
- const streamRef = useRef(null);
679
- const sarvamChunksRef = useRef([]);
680
- const spaceTimerRef = useRef(null);
681
- const isPushToTalkRef = useRef(false);
682
- useEffect(() => {
944
+ const [isOpen, setIsOpen] = useState2(false);
945
+ const [description, setDescription] = useState2("");
946
+ const [isSubmitting, setIsSubmitting] = useState2(false);
947
+ const [submitted, setSubmitted] = useState2(false);
948
+ const [screenshots, setScreenshots] = useState2([]);
949
+ const [previewIndex, setPreviewIndex] = useState2(null);
950
+ const [annotatingIndex, setAnnotatingIndex] = useState2(null);
951
+ const fileInputRef = useRef2(null);
952
+ const modalRef = useRef2(null);
953
+ const previewImgRef = useRef2(null);
954
+ const textareaRef = useRef2(null);
955
+ const recognitionRef = useRef2(null);
956
+ const voiceBaseRef = useRef2("");
957
+ const usingWebSpeechRef = useRef2(false);
958
+ const textBeforeVoiceRef = useRef2("");
959
+ const mediaRecorderRef = useRef2(null);
960
+ const streamRef = useRef2(null);
961
+ const sarvamChunksRef = useRef2([]);
962
+ const spaceTimerRef = useRef2(null);
963
+ const isPushToTalkRef = useRef2(false);
964
+ useEffect2(() => {
683
965
  if (!isOpen) return;
684
966
  const dialogs = Array.from(
685
967
  document.querySelectorAll(
@@ -689,14 +971,17 @@ function ReportDialog({
689
971
  dialogs.forEach((d) => d.setAttribute("inert", ""));
690
972
  return () => dialogs.forEach((d) => d.removeAttribute("inert"));
691
973
  }, [isOpen]);
692
- const [step, setStep] = useState(1);
693
- const [reportType, setReportType] = useState("BUG");
694
- const [severity, setSeverity] = useState("medium");
695
- const [validationError, setValidationError] = useState(null);
696
- const [placeholderIdx, setPlaceholderIdx] = useState(0);
974
+ const [step, setStep] = useState2(1);
975
+ const [reportType, setReportType] = useState2("BUG");
976
+ const [severity, setSeverity] = useState2("medium");
977
+ const [validationError, setValidationError] = useState2(null);
978
+ const [placeholderIdx, setPlaceholderIdx] = useState2(0);
697
979
  const availableTypes = types != null ? types : [
698
980
  "BUG",
699
981
  "FEATURE_REQUEST",
982
+ "UI_IMPROVEMENT",
983
+ "PERFORMANCE",
984
+ "SECURITY",
700
985
  "QUESTION",
701
986
  "OTHER"
702
987
  ];
@@ -725,7 +1010,13 @@ function ReportDialog({
725
1010
  scale: 0.5,
726
1011
  logging: false,
727
1012
  useCORS: true,
728
- allowTaint: true
1013
+ allowTaint: true,
1014
+ x: window.scrollX,
1015
+ y: window.scrollY,
1016
+ width: window.innerWidth,
1017
+ height: window.innerHeight,
1018
+ windowWidth: window.innerWidth,
1019
+ windowHeight: window.innerHeight
729
1020
  });
730
1021
  setScreenshots([canvas.toDataURL("image/jpeg", 0.6)]);
731
1022
  } catch (e) {
@@ -744,14 +1035,20 @@ function ReportDialog({
744
1035
  scale: 0.5,
745
1036
  logging: false,
746
1037
  useCORS: true,
747
- allowTaint: true
1038
+ allowTaint: true,
1039
+ x: window.scrollX,
1040
+ y: window.scrollY,
1041
+ width: window.innerWidth,
1042
+ height: window.innerHeight,
1043
+ windowWidth: window.innerWidth,
1044
+ windowHeight: window.innerHeight
748
1045
  });
749
1046
  setScreenshots([canvas.toDataURL("image/jpeg", 0.6)]);
750
1047
  } catch (e) {
751
1048
  }
752
1049
  setIsOpen(true);
753
1050
  };
754
- useEffect(() => {
1051
+ useEffect2(() => {
755
1052
  const handler = (e) => {
756
1053
  if (isOpen) return;
757
1054
  const detail = e.detail;
@@ -765,7 +1062,7 @@ function ReportDialog({
765
1062
  window.addEventListener("glitchgrab:open-report", handler);
766
1063
  return () => window.removeEventListener("glitchgrab:open-report", handler);
767
1064
  }, [isOpen, handleOpen]);
768
- useEffect(() => {
1065
+ useEffect2(() => {
769
1066
  if (!isOpen) return;
770
1067
  const handleEsc = (e) => {
771
1068
  if (e.key === "Escape") {
@@ -776,8 +1073,8 @@ function ReportDialog({
776
1073
  document.addEventListener("keydown", handleEsc);
777
1074
  return () => document.removeEventListener("keydown", handleEsc);
778
1075
  }, [isOpen, previewIndex]);
779
- useEffect(() => {
780
- if (previewIndex === null) return;
1076
+ useEffect2(() => {
1077
+ if (previewIndex === null || annotatingIndex !== null) return;
781
1078
  const handlePointerDown = (e) => {
782
1079
  var _a;
783
1080
  if (!((_a = previewImgRef.current) == null ? void 0 : _a.contains(e.target))) {
@@ -786,8 +1083,8 @@ function ReportDialog({
786
1083
  };
787
1084
  document.addEventListener("pointerdown", handlePointerDown, true);
788
1085
  return () => document.removeEventListener("pointerdown", handlePointerDown, true);
789
- }, [previewIndex]);
790
- useEffect(() => {
1086
+ }, [previewIndex, annotatingIndex]);
1087
+ useEffect2(() => {
791
1088
  if (!isOpen) return;
792
1089
  const handlePaste = (e) => {
793
1090
  var _a;
@@ -812,7 +1109,7 @@ function ReportDialog({
812
1109
  window.addEventListener("paste", handlePaste);
813
1110
  return () => window.removeEventListener("paste", handlePaste);
814
1111
  }, [isOpen]);
815
- useEffect(() => {
1112
+ useEffect2(() => {
816
1113
  if (!isOpen || !transcribeAudio2) return;
817
1114
  const id = setInterval(() => {
818
1115
  setPlaceholderIdx((i) => (i + 1) % 2);
@@ -1029,9 +1326,9 @@ function ReportDialog({
1029
1326
  }
1030
1327
  };
1031
1328
  if (!mounted) return null;
1032
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1329
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
1033
1330
  isOpen && createPortal(
1034
- /* @__PURE__ */ jsx("style", { children: `
1331
+ /* @__PURE__ */ jsx2("style", { children: `
1035
1332
  @keyframes gg-pulse{0%,100%{opacity:1}50%{opacity:0.35}}
1036
1333
  @keyframes gg-b1{0%,100%{height:3px}40%{height:13px}}
1037
1334
  @keyframes gg-b2{0%,100%{height:8px}50%{height:3px}}
@@ -1041,7 +1338,7 @@ function ReportDialog({
1041
1338
  document.body
1042
1339
  ),
1043
1340
  isOpen && createPortal(
1044
- /* @__PURE__ */ jsx(
1341
+ /* @__PURE__ */ jsx2(
1045
1342
  "div",
1046
1343
  {
1047
1344
  style: {
@@ -1060,7 +1357,7 @@ function ReportDialog({
1060
1357
  },
1061
1358
  onPointerDown: (e) => e.stopPropagation(),
1062
1359
  onFocus: (e) => e.stopPropagation(),
1063
- children: /* @__PURE__ */ jsxs(
1360
+ children: /* @__PURE__ */ jsxs2(
1064
1361
  "div",
1065
1362
  {
1066
1363
  ref: modalRef,
@@ -1079,7 +1376,7 @@ function ReportDialog({
1079
1376
  isolation: "isolate"
1080
1377
  },
1081
1378
  children: [
1082
- /* @__PURE__ */ jsxs(
1379
+ /* @__PURE__ */ jsxs2(
1083
1380
  "div",
1084
1381
  {
1085
1382
  style: {
@@ -1087,7 +1384,7 @@ function ReportDialog({
1087
1384
  borderBottom: `1px solid ${t.border}`
1088
1385
  },
1089
1386
  children: [
1090
- /* @__PURE__ */ jsxs(
1387
+ /* @__PURE__ */ jsxs2(
1091
1388
  "div",
1092
1389
  {
1093
1390
  style: {
@@ -1096,7 +1393,7 @@ function ReportDialog({
1096
1393
  alignItems: "center"
1097
1394
  },
1098
1395
  children: [
1099
- /* @__PURE__ */ jsxs(
1396
+ /* @__PURE__ */ jsxs2(
1100
1397
  "div",
1101
1398
  {
1102
1399
  style: {
@@ -1105,7 +1402,7 @@ function ReportDialog({
1105
1402
  gap: "8px"
1106
1403
  },
1107
1404
  children: [
1108
- step > 1 && /* @__PURE__ */ jsx(
1405
+ step > 1 && /* @__PURE__ */ jsx2(
1109
1406
  "button",
1110
1407
  {
1111
1408
  type: "button",
@@ -1119,14 +1416,14 @@ function ReportDialog({
1119
1416
  alignItems: "center"
1120
1417
  },
1121
1418
  "aria-label": "Back",
1122
- children: /* @__PURE__ */ jsx(
1419
+ children: /* @__PURE__ */ jsx2(
1123
1420
  "svg",
1124
1421
  {
1125
1422
  width: "16",
1126
1423
  height: "16",
1127
1424
  viewBox: "0 0 16 16",
1128
1425
  fill: "none",
1129
- children: /* @__PURE__ */ jsx(
1426
+ children: /* @__PURE__ */ jsx2(
1130
1427
  "path",
1131
1428
  {
1132
1429
  d: "M10 3L5 8L10 13",
@@ -1140,7 +1437,7 @@ function ReportDialog({
1140
1437
  )
1141
1438
  }
1142
1439
  ),
1143
- /* @__PURE__ */ jsx(
1440
+ /* @__PURE__ */ jsx2(
1144
1441
  "span",
1145
1442
  {
1146
1443
  style: {
@@ -1154,7 +1451,7 @@ function ReportDialog({
1154
1451
  ]
1155
1452
  }
1156
1453
  ),
1157
- /* @__PURE__ */ jsx(
1454
+ /* @__PURE__ */ jsx2(
1158
1455
  "button",
1159
1456
  {
1160
1457
  type: "button",
@@ -1169,7 +1466,7 @@ function ReportDialog({
1169
1466
  justifyContent: "center"
1170
1467
  },
1171
1468
  "aria-label": "Close",
1172
- children: /* @__PURE__ */ jsx(
1469
+ children: /* @__PURE__ */ jsx2(
1173
1470
  "svg",
1174
1471
  {
1175
1472
  width: "16",
@@ -1177,7 +1474,7 @@ function ReportDialog({
1177
1474
  viewBox: "0 0 16 16",
1178
1475
  fill: "none",
1179
1476
  style: { display: "block" },
1180
- children: /* @__PURE__ */ jsx(
1477
+ children: /* @__PURE__ */ jsx2(
1181
1478
  "path",
1182
1479
  {
1183
1480
  d: "M4 4L12 12M12 4L4 12",
@@ -1193,7 +1490,7 @@ function ReportDialog({
1193
1490
  ]
1194
1491
  }
1195
1492
  ),
1196
- /* @__PURE__ */ jsx(
1493
+ /* @__PURE__ */ jsx2(
1197
1494
  "div",
1198
1495
  {
1199
1496
  style: {
@@ -1203,12 +1500,12 @@ function ReportDialog({
1203
1500
  gap: "0",
1204
1501
  marginTop: "12px"
1205
1502
  },
1206
- children: [1, 2].map((s, i) => /* @__PURE__ */ jsxs(
1503
+ children: [1, 2].map((s, i) => /* @__PURE__ */ jsxs2(
1207
1504
  "div",
1208
1505
  {
1209
1506
  style: { display: "flex", alignItems: "center" },
1210
1507
  children: [
1211
- /* @__PURE__ */ jsx(
1508
+ /* @__PURE__ */ jsx2(
1212
1509
  "div",
1213
1510
  {
1214
1511
  style: {
@@ -1220,7 +1517,7 @@ function ReportDialog({
1220
1517
  }
1221
1518
  }
1222
1519
  ),
1223
- i < 1 && /* @__PURE__ */ jsx(
1520
+ i < 1 && /* @__PURE__ */ jsx2(
1224
1521
  "div",
1225
1522
  {
1226
1523
  style: {
@@ -1240,7 +1537,7 @@ function ReportDialog({
1240
1537
  ]
1241
1538
  }
1242
1539
  ),
1243
- /* @__PURE__ */ jsx("div", { style: { padding: "16px" }, children: submitted ? /* @__PURE__ */ jsxs(
1540
+ /* @__PURE__ */ jsx2("div", { style: { padding: "16px" }, children: submitted ? /* @__PURE__ */ jsxs2(
1244
1541
  "div",
1245
1542
  {
1246
1543
  style: {
@@ -1255,8 +1552,8 @@ function ReportDialog({
1255
1552
  " sent. Thank you!"
1256
1553
  ]
1257
1554
  }
1258
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1259
- step === 1 && /* @__PURE__ */ jsx(
1555
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
1556
+ step === 1 && /* @__PURE__ */ jsx2(
1260
1557
  "div",
1261
1558
  {
1262
1559
  style: {
@@ -1264,7 +1561,7 @@ function ReportDialog({
1264
1561
  gridTemplateColumns: "1fr 1fr",
1265
1562
  gap: "8px"
1266
1563
  },
1267
- children: availableTypes.map((type) => /* @__PURE__ */ jsxs(
1564
+ children: availableTypes.map((type) => /* @__PURE__ */ jsxs2(
1268
1565
  "button",
1269
1566
  {
1270
1567
  type: "button",
@@ -1294,8 +1591,8 @@ function ReportDialog({
1294
1591
  },
1295
1592
  children: [
1296
1593
  getTypeIcon(type, t.accent),
1297
- /* @__PURE__ */ jsx("span", { style: { fontSize: "13px", fontWeight: 600 }, children: getTypeLabel(type) }),
1298
- /* @__PURE__ */ jsx(
1594
+ /* @__PURE__ */ jsx2("span", { style: { fontSize: "13px", fontWeight: 600 }, children: getTypeLabel(type) }),
1595
+ /* @__PURE__ */ jsx2(
1299
1596
  "span",
1300
1597
  {
1301
1598
  style: {
@@ -1312,9 +1609,9 @@ function ReportDialog({
1312
1609
  ))
1313
1610
  }
1314
1611
  ),
1315
- step === 2 && /* @__PURE__ */ jsxs(Fragment, { children: [
1316
- /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
1317
- /* @__PURE__ */ jsx(
1612
+ step === 2 && /* @__PURE__ */ jsxs2(Fragment, { children: [
1613
+ /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1614
+ /* @__PURE__ */ jsx2(
1318
1615
  "textarea",
1319
1616
  {
1320
1617
  ref: textareaRef,
@@ -1355,7 +1652,7 @@ function ReportDialog({
1355
1652
  autoFocus: true
1356
1653
  }
1357
1654
  ),
1358
- (isListening || isTranscribing) && /* @__PURE__ */ jsxs(
1655
+ (isListening || isTranscribing) && /* @__PURE__ */ jsxs2(
1359
1656
  "span",
1360
1657
  {
1361
1658
  style: {
@@ -1373,7 +1670,7 @@ function ReportDialog({
1373
1670
  zIndex: 1
1374
1671
  },
1375
1672
  children: [
1376
- /* @__PURE__ */ jsx(
1673
+ /* @__PURE__ */ jsx2(
1377
1674
  "span",
1378
1675
  {
1379
1676
  style: {
@@ -1388,7 +1685,7 @@ function ReportDialog({
1388
1685
  }
1389
1686
  ),
1390
1687
  isTranscribing ? "Transcribing\u2026" : "REC",
1391
- isListening && !isTranscribing && /* @__PURE__ */ jsx(
1688
+ isListening && !isTranscribing && /* @__PURE__ */ jsx2(
1392
1689
  "span",
1393
1690
  {
1394
1691
  style: {
@@ -1415,7 +1712,7 @@ function ReportDialog({
1415
1712
  dur: "0.55s",
1416
1713
  delay: "0.15s"
1417
1714
  }
1418
- ].map((b, i) => /* @__PURE__ */ jsx(
1715
+ ].map((b, i) => /* @__PURE__ */ jsx2(
1419
1716
  "span",
1420
1717
  {
1421
1718
  style: {
@@ -1435,7 +1732,7 @@ function ReportDialog({
1435
1732
  ]
1436
1733
  }
1437
1734
  ),
1438
- enhanceText2 && /* @__PURE__ */ jsxs(
1735
+ enhanceText2 && /* @__PURE__ */ jsxs2(
1439
1736
  "button",
1440
1737
  {
1441
1738
  type: "button",
@@ -1480,7 +1777,7 @@ function ReportDialog({
1480
1777
  },
1481
1778
  title: "Polish grammar \u2014 preserves your meaning",
1482
1779
  children: [
1483
- /* @__PURE__ */ jsx(
1780
+ /* @__PURE__ */ jsx2(
1484
1781
  "svg",
1485
1782
  {
1486
1783
  width: "11",
@@ -1488,7 +1785,7 @@ function ReportDialog({
1488
1785
  viewBox: "0 0 24 24",
1489
1786
  fill: "none",
1490
1787
  "aria-hidden": "true",
1491
- children: /* @__PURE__ */ jsx(
1788
+ children: /* @__PURE__ */ jsx2(
1492
1789
  "path",
1493
1790
  {
1494
1791
  d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3zM19 15l.75 2.25L22 18l-2.25.75L19 21l-.75-2.25L16 18l2.25-.75L19 15z",
@@ -1503,7 +1800,7 @@ function ReportDialog({
1503
1800
  ]
1504
1801
  }
1505
1802
  ),
1506
- transcribeAudio2 && /* @__PURE__ */ jsx(
1803
+ transcribeAudio2 && /* @__PURE__ */ jsx2(
1507
1804
  "button",
1508
1805
  {
1509
1806
  type: "button",
@@ -1529,7 +1826,7 @@ function ReportDialog({
1529
1826
  padding: 0,
1530
1827
  transition: "border-color 0.2s ease, color 0.2s ease"
1531
1828
  },
1532
- children: isListening ? /* @__PURE__ */ jsx(
1829
+ children: isListening ? /* @__PURE__ */ jsx2(
1533
1830
  "svg",
1534
1831
  {
1535
1832
  width: "12",
@@ -1537,7 +1834,7 @@ function ReportDialog({
1537
1834
  viewBox: "0 0 24 24",
1538
1835
  fill: "currentColor",
1539
1836
  "aria-hidden": "true",
1540
- children: /* @__PURE__ */ jsx(
1837
+ children: /* @__PURE__ */ jsx2(
1541
1838
  "rect",
1542
1839
  {
1543
1840
  x: "6",
@@ -1548,7 +1845,7 @@ function ReportDialog({
1548
1845
  }
1549
1846
  )
1550
1847
  }
1551
- ) : /* @__PURE__ */ jsxs(
1848
+ ) : /* @__PURE__ */ jsxs2(
1552
1849
  "svg",
1553
1850
  {
1554
1851
  width: "13",
@@ -1557,7 +1854,7 @@ function ReportDialog({
1557
1854
  fill: "none",
1558
1855
  "aria-hidden": "true",
1559
1856
  children: [
1560
- /* @__PURE__ */ jsx(
1857
+ /* @__PURE__ */ jsx2(
1561
1858
  "rect",
1562
1859
  {
1563
1860
  x: "9",
@@ -1569,7 +1866,7 @@ function ReportDialog({
1569
1866
  strokeWidth: "1.8"
1570
1867
  }
1571
1868
  ),
1572
- /* @__PURE__ */ jsx(
1869
+ /* @__PURE__ */ jsx2(
1573
1870
  "path",
1574
1871
  {
1575
1872
  d: "M5 10a7 7 0 0014 0M12 19v3M9 22h6",
@@ -1584,7 +1881,7 @@ function ReportDialog({
1584
1881
  }
1585
1882
  )
1586
1883
  ] }),
1587
- transcribeAudio2 && !isListening && !isTranscribing && /* @__PURE__ */ jsxs(
1884
+ transcribeAudio2 && !isListening && !isTranscribing && /* @__PURE__ */ jsxs2(
1588
1885
  "div",
1589
1886
  {
1590
1887
  style: {
@@ -1598,16 +1895,16 @@ function ReportDialog({
1598
1895
  userSelect: "none"
1599
1896
  },
1600
1897
  children: [
1601
- /* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1602
- /* @__PURE__ */ jsx("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
1603
- /* @__PURE__ */ jsx("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1604
- /* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "19", y2: "22" })
1898
+ /* @__PURE__ */ jsxs2("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1899
+ /* @__PURE__ */ jsx2("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
1900
+ /* @__PURE__ */ jsx2("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1901
+ /* @__PURE__ */ jsx2("line", { x1: "12", x2: "12", y1: "19", y2: "22" })
1605
1902
  ] }),
1606
1903
  "Hold Space to speak \u2014 we'll transcribe it"
1607
1904
  ]
1608
1905
  }
1609
1906
  ),
1610
- isEnhanced && originalDescription !== null && /* @__PURE__ */ jsxs(
1907
+ isEnhanced && originalDescription !== null && /* @__PURE__ */ jsxs2(
1611
1908
  "div",
1612
1909
  {
1613
1910
  style: {
@@ -1621,7 +1918,7 @@ function ReportDialog({
1621
1918
  border: `1px solid ${t.accent}40`
1622
1919
  },
1623
1920
  children: [
1624
- /* @__PURE__ */ jsx(
1921
+ /* @__PURE__ */ jsx2(
1625
1922
  "svg",
1626
1923
  {
1627
1924
  width: "12",
@@ -1629,7 +1926,7 @@ function ReportDialog({
1629
1926
  viewBox: "0 0 24 24",
1630
1927
  fill: "none",
1631
1928
  style: { flexShrink: 0 },
1632
- children: /* @__PURE__ */ jsx(
1929
+ children: /* @__PURE__ */ jsx2(
1633
1930
  "path",
1634
1931
  {
1635
1932
  d: "M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z",
@@ -1640,7 +1937,7 @@ function ReportDialog({
1640
1937
  )
1641
1938
  }
1642
1939
  ),
1643
- /* @__PURE__ */ jsx(
1940
+ /* @__PURE__ */ jsx2(
1644
1941
  "span",
1645
1942
  {
1646
1943
  style: {
@@ -1651,7 +1948,7 @@ function ReportDialog({
1651
1948
  children: "AI enhanced"
1652
1949
  }
1653
1950
  ),
1654
- /* @__PURE__ */ jsx(
1951
+ /* @__PURE__ */ jsx2(
1655
1952
  "button",
1656
1953
  {
1657
1954
  type: "button",
@@ -1673,7 +1970,7 @@ function ReportDialog({
1673
1970
  children: "Keep"
1674
1971
  }
1675
1972
  ),
1676
- /* @__PURE__ */ jsx(
1973
+ /* @__PURE__ */ jsx2(
1677
1974
  "button",
1678
1975
  {
1679
1976
  type: "button",
@@ -1699,7 +1996,7 @@ function ReportDialog({
1699
1996
  ]
1700
1997
  }
1701
1998
  ),
1702
- voiceError && /* @__PURE__ */ jsx(
1999
+ voiceError && /* @__PURE__ */ jsx2(
1703
2000
  "p",
1704
2001
  {
1705
2002
  style: {
@@ -1711,8 +2008,8 @@ function ReportDialog({
1711
2008
  children: voiceError
1712
2009
  }
1713
2010
  ),
1714
- /* @__PURE__ */ jsxs("div", { style: { marginTop: "10px" }, children: [
1715
- /* @__PURE__ */ jsxs(
2011
+ /* @__PURE__ */ jsxs2("div", { style: { marginTop: "10px" }, children: [
2012
+ /* @__PURE__ */ jsxs2(
1716
2013
  "span",
1717
2014
  {
1718
2015
  style: {
@@ -1728,7 +2025,7 @@ function ReportDialog({
1728
2025
  ]
1729
2026
  }
1730
2027
  ),
1731
- screenshots.length > 0 && /* @__PURE__ */ jsx(
2028
+ screenshots.length > 0 && /* @__PURE__ */ jsx2(
1732
2029
  "div",
1733
2030
  {
1734
2031
  style: {
@@ -1737,7 +2034,7 @@ function ReportDialog({
1737
2034
  gap: "8px",
1738
2035
  marginBottom: "8px"
1739
2036
  },
1740
- children: screenshots.map((src, i) => /* @__PURE__ */ jsxs(
2037
+ children: screenshots.map((src, i) => /* @__PURE__ */ jsxs2(
1741
2038
  "div",
1742
2039
  {
1743
2040
  style: {
@@ -1746,7 +2043,7 @@ function ReportDialog({
1746
2043
  height: "56px"
1747
2044
  },
1748
2045
  children: [
1749
- /* @__PURE__ */ jsx(
2046
+ /* @__PURE__ */ jsx2(
1750
2047
  "img",
1751
2048
  {
1752
2049
  src,
@@ -1764,7 +2061,7 @@ function ReportDialog({
1764
2061
  }
1765
2062
  }
1766
2063
  ),
1767
- /* @__PURE__ */ jsx(
2064
+ /* @__PURE__ */ jsx2(
1768
2065
  "button",
1769
2066
  {
1770
2067
  type: "button",
@@ -1790,14 +2087,14 @@ function ReportDialog({
1790
2087
  alignItems: "center",
1791
2088
  justifyContent: "center"
1792
2089
  },
1793
- children: /* @__PURE__ */ jsx(
2090
+ children: /* @__PURE__ */ jsx2(
1794
2091
  "svg",
1795
2092
  {
1796
2093
  width: "8",
1797
2094
  height: "8",
1798
2095
  viewBox: "0 0 10 10",
1799
2096
  fill: "none",
1800
- children: /* @__PURE__ */ jsx(
2097
+ children: /* @__PURE__ */ jsx2(
1801
2098
  "path",
1802
2099
  {
1803
2100
  d: "M1 1L9 9M9 1L1 9",
@@ -1809,6 +2106,52 @@ function ReportDialog({
1809
2106
  }
1810
2107
  )
1811
2108
  }
2109
+ ),
2110
+ /* @__PURE__ */ jsx2(
2111
+ "button",
2112
+ {
2113
+ type: "button",
2114
+ onClick: () => setAnnotatingIndex(i),
2115
+ "aria-label": `Annotate screenshot ${i + 1}`,
2116
+ title: "Annotate",
2117
+ style: {
2118
+ position: "absolute",
2119
+ top: "50%",
2120
+ left: "50%",
2121
+ transform: "translate(-50%, -50%)",
2122
+ width: "24px",
2123
+ height: "24px",
2124
+ borderRadius: "50%",
2125
+ border: "none",
2126
+ background: t.accent,
2127
+ color: t.accentText,
2128
+ padding: 0,
2129
+ cursor: "pointer",
2130
+ display: "flex",
2131
+ alignItems: "center",
2132
+ justifyContent: "center",
2133
+ boxShadow: "0 2px 8px rgba(0,0,0,0.45)"
2134
+ },
2135
+ children: /* @__PURE__ */ jsx2(
2136
+ "svg",
2137
+ {
2138
+ width: "12",
2139
+ height: "12",
2140
+ viewBox: "0 0 24 24",
2141
+ fill: "none",
2142
+ children: /* @__PURE__ */ jsx2(
2143
+ "path",
2144
+ {
2145
+ d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z",
2146
+ stroke: "currentColor",
2147
+ strokeWidth: "2.2",
2148
+ strokeLinecap: "round",
2149
+ strokeLinejoin: "round"
2150
+ }
2151
+ )
2152
+ }
2153
+ )
2154
+ }
1812
2155
  )
1813
2156
  ]
1814
2157
  },
@@ -1816,7 +2159,7 @@ function ReportDialog({
1816
2159
  ))
1817
2160
  }
1818
2161
  ),
1819
- /* @__PURE__ */ jsx(
2162
+ /* @__PURE__ */ jsx2(
1820
2163
  "div",
1821
2164
  {
1822
2165
  onClick: () => {
@@ -1852,7 +2195,7 @@ function ReportDialog({
1852
2195
  background: screenshotDragOver ? isDark ? "rgba(34,211,238,0.06)" : "rgba(8,145,178,0.04)" : "transparent",
1853
2196
  transition: "border-color 0.15s ease, background 0.15s ease"
1854
2197
  },
1855
- children: screenshots.length > 0 ? /* @__PURE__ */ jsx(
2198
+ children: screenshots.length > 0 ? /* @__PURE__ */ jsx2(
1856
2199
  "p",
1857
2200
  {
1858
2201
  style: {
@@ -1863,8 +2206,8 @@ function ReportDialog({
1863
2206
  },
1864
2207
  children: screenshotDragOver ? "Drop to attach" : "+ Add more \xB7 Drag & drop \xB7 Paste"
1865
2208
  }
1866
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1867
- /* @__PURE__ */ jsxs(
2209
+ ) : /* @__PURE__ */ jsxs2(Fragment, { children: [
2210
+ /* @__PURE__ */ jsxs2(
1868
2211
  "svg",
1869
2212
  {
1870
2213
  width: "22",
@@ -1877,7 +2220,7 @@ function ReportDialog({
1877
2220
  opacity: 0.45
1878
2221
  },
1879
2222
  children: [
1880
- /* @__PURE__ */ jsx(
2223
+ /* @__PURE__ */ jsx2(
1881
2224
  "rect",
1882
2225
  {
1883
2226
  x: "3",
@@ -1889,7 +2232,7 @@ function ReportDialog({
1889
2232
  strokeWidth: "1.5"
1890
2233
  }
1891
2234
  ),
1892
- /* @__PURE__ */ jsx(
2235
+ /* @__PURE__ */ jsx2(
1893
2236
  "circle",
1894
2237
  {
1895
2238
  cx: "8.5",
@@ -1899,7 +2242,7 @@ function ReportDialog({
1899
2242
  strokeWidth: "1.5"
1900
2243
  }
1901
2244
  ),
1902
- /* @__PURE__ */ jsx(
2245
+ /* @__PURE__ */ jsx2(
1903
2246
  "path",
1904
2247
  {
1905
2248
  d: "M21 15l-5-5L5 21",
@@ -1912,7 +2255,7 @@ function ReportDialog({
1912
2255
  ]
1913
2256
  }
1914
2257
  ),
1915
- /* @__PURE__ */ jsx(
2258
+ /* @__PURE__ */ jsx2(
1916
2259
  "p",
1917
2260
  {
1918
2261
  style: {
@@ -1924,7 +2267,7 @@ function ReportDialog({
1924
2267
  children: screenshotDragOver ? "Drop to attach" : "Add screenshots"
1925
2268
  }
1926
2269
  ),
1927
- /* @__PURE__ */ jsx(
2270
+ /* @__PURE__ */ jsx2(
1928
2271
  "p",
1929
2272
  {
1930
2273
  style: {
@@ -1939,8 +2282,8 @@ function ReportDialog({
1939
2282
  }
1940
2283
  )
1941
2284
  ] }),
1942
- showSeverity && reportType === "BUG" && /* @__PURE__ */ jsxs("div", { style: { marginTop: "10px" }, children: [
1943
- /* @__PURE__ */ jsx(
2285
+ showSeverity && reportType === "BUG" && /* @__PURE__ */ jsxs2("div", { style: { marginTop: "10px" }, children: [
2286
+ /* @__PURE__ */ jsx2(
1944
2287
  "span",
1945
2288
  {
1946
2289
  style: {
@@ -1952,7 +2295,7 @@ function ReportDialog({
1952
2295
  children: "Severity"
1953
2296
  }
1954
2297
  ),
1955
- /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "6px" }, children: ["low", "medium", "high"].map((s) => /* @__PURE__ */ jsx(
2298
+ /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: "6px" }, children: ["low", "medium", "high"].map((s) => /* @__PURE__ */ jsx2(
1956
2299
  "button",
1957
2300
  {
1958
2301
  type: "button",
@@ -1976,7 +2319,7 @@ function ReportDialog({
1976
2319
  s
1977
2320
  )) })
1978
2321
  ] }),
1979
- validationError && /* @__PURE__ */ jsx(
2322
+ validationError && /* @__PURE__ */ jsx2(
1980
2323
  "p",
1981
2324
  {
1982
2325
  style: {
@@ -1987,7 +2330,7 @@ function ReportDialog({
1987
2330
  children: validationError
1988
2331
  }
1989
2332
  ),
1990
- /* @__PURE__ */ jsx(
2333
+ /* @__PURE__ */ jsx2(
1991
2334
  "button",
1992
2335
  {
1993
2336
  type: "button",
@@ -2012,7 +2355,7 @@ function ReportDialog({
2012
2355
  )
2013
2356
  ] })
2014
2357
  ] }) }),
2015
- /* @__PURE__ */ jsx(
2358
+ /* @__PURE__ */ jsx2(
2016
2359
  "div",
2017
2360
  {
2018
2361
  style: {
@@ -2020,7 +2363,7 @@ function ReportDialog({
2020
2363
  borderTop: `1px solid ${t.border}`,
2021
2364
  textAlign: "center"
2022
2365
  },
2023
- children: /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: t.textMuted }, children: "Powered by Glitchgrab" })
2366
+ children: /* @__PURE__ */ jsx2("span", { style: { fontSize: "11px", color: t.textMuted }, children: "Powered by Glitchgrab" })
2024
2367
  }
2025
2368
  )
2026
2369
  ]
@@ -2030,7 +2373,7 @@ function ReportDialog({
2030
2373
  ),
2031
2374
  document.body
2032
2375
  ),
2033
- /* @__PURE__ */ jsx(
2376
+ /* @__PURE__ */ jsx2(
2034
2377
  "input",
2035
2378
  {
2036
2379
  ref: fileInputRef,
@@ -2042,7 +2385,7 @@ function ReportDialog({
2042
2385
  }
2043
2386
  ),
2044
2387
  previewIndex !== null && screenshots[previewIndex] && createPortal(
2045
- /* @__PURE__ */ jsxs(
2388
+ /* @__PURE__ */ jsxs2(
2046
2389
  "div",
2047
2390
  {
2048
2391
  style: {
@@ -2063,37 +2406,114 @@ function ReportDialog({
2063
2406
  },
2064
2407
  onMouseDown: (e) => e.stopPropagation(),
2065
2408
  children: [
2066
- /* @__PURE__ */ jsx(
2067
- "img",
2409
+ /* @__PURE__ */ jsxs2(
2410
+ "div",
2068
2411
  {
2069
2412
  ref: previewImgRef,
2070
- src: screenshots[previewIndex],
2071
- alt: "Screenshot preview",
2413
+ style: { position: "relative", maxWidth: "100%" },
2072
2414
  onClick: (e) => e.stopPropagation(),
2073
- style: {
2074
- maxWidth: "100%",
2075
- maxHeight: "calc(100vh - 80px)",
2076
- borderRadius: "8px",
2077
- objectFit: "contain",
2078
- cursor: "default"
2079
- }
2415
+ children: [
2416
+ /* @__PURE__ */ jsx2(
2417
+ "img",
2418
+ {
2419
+ src: screenshots[previewIndex],
2420
+ alt: "Screenshot preview",
2421
+ style: {
2422
+ maxWidth: "100%",
2423
+ maxHeight: "calc(100vh - 80px)",
2424
+ borderRadius: "8px",
2425
+ objectFit: "contain",
2426
+ cursor: "default",
2427
+ display: "block"
2428
+ }
2429
+ }
2430
+ ),
2431
+ /* @__PURE__ */ jsxs2(
2432
+ "button",
2433
+ {
2434
+ type: "button",
2435
+ onClick: (e) => {
2436
+ e.stopPropagation();
2437
+ setAnnotatingIndex(previewIndex);
2438
+ },
2439
+ style: {
2440
+ position: "absolute",
2441
+ top: "12px",
2442
+ right: "12px",
2443
+ display: "inline-flex",
2444
+ alignItems: "center",
2445
+ gap: "6px",
2446
+ padding: "8px 14px",
2447
+ borderRadius: "999px",
2448
+ border: "none",
2449
+ background: t.accent,
2450
+ color: t.accentText,
2451
+ fontSize: "13px",
2452
+ fontWeight: 700,
2453
+ cursor: "pointer",
2454
+ fontFamily: "inherit",
2455
+ boxShadow: "0 4px 14px rgba(0,0,0,0.35)",
2456
+ animation: "gg-pulse 2s ease-in-out infinite"
2457
+ },
2458
+ children: [
2459
+ /* @__PURE__ */ jsx2("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx2(
2460
+ "path",
2461
+ {
2462
+ d: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z",
2463
+ stroke: "currentColor",
2464
+ strokeWidth: "2",
2465
+ strokeLinecap: "round",
2466
+ strokeLinejoin: "round"
2467
+ }
2468
+ ) }),
2469
+ "Annotate"
2470
+ ]
2471
+ }
2472
+ )
2473
+ ]
2080
2474
  }
2081
2475
  ),
2082
- /* @__PURE__ */ jsx(
2083
- "span",
2476
+ /* @__PURE__ */ jsx2(
2477
+ "div",
2084
2478
  {
2085
2479
  style: {
2086
2480
  marginTop: "12px",
2087
- color: t.textMuted,
2088
- fontSize: "12px"
2481
+ display: "flex",
2482
+ alignItems: "center",
2483
+ gap: "12px"
2089
2484
  },
2090
- children: screenshots.length > 1 ? `${previewIndex + 1} / ${screenshots.length} \xB7 Click outside to close` : "Click outside to close"
2485
+ children: /* @__PURE__ */ jsx2(
2486
+ "span",
2487
+ {
2488
+ style: {
2489
+ color: t.textMuted,
2490
+ fontSize: "12px"
2491
+ },
2492
+ children: screenshots.length > 1 ? `${previewIndex + 1} / ${screenshots.length} \xB7 Click outside to close` : "Click outside to close"
2493
+ }
2494
+ )
2091
2495
  }
2092
2496
  )
2093
2497
  ]
2094
2498
  }
2095
2499
  ),
2096
2500
  document.body
2501
+ ),
2502
+ annotatingIndex !== null && screenshots[annotatingIndex] && createPortal(
2503
+ /* @__PURE__ */ jsx2(
2504
+ AnnotationCanvas,
2505
+ {
2506
+ imageSrc: screenshots[annotatingIndex],
2507
+ onCancel: () => setAnnotatingIndex(null),
2508
+ onSave: (dataUrl) => {
2509
+ setScreenshots(
2510
+ (prev) => prev.map((s, i) => i === annotatingIndex ? dataUrl : s)
2511
+ );
2512
+ setAnnotatingIndex(null);
2513
+ }
2514
+ }
2515
+ ),
2516
+ document.body
2097
2517
  )
2098
2518
  ] });
2099
2519
  }
@@ -2103,6 +2523,12 @@ function getTypeLabel(type) {
2103
2523
  return "Bug Report";
2104
2524
  case "FEATURE_REQUEST":
2105
2525
  return "Feature Request";
2526
+ case "UI_IMPROVEMENT":
2527
+ return "UI Improvement";
2528
+ case "PERFORMANCE":
2529
+ return "Performance";
2530
+ case "SECURITY":
2531
+ return "Security";
2106
2532
  case "QUESTION":
2107
2533
  return "Question";
2108
2534
  case "OTHER":
@@ -2115,6 +2541,12 @@ function getTypeSubtitle(type) {
2115
2541
  return "Something isn't working";
2116
2542
  case "FEATURE_REQUEST":
2117
2543
  return "Suggest an improvement";
2544
+ case "UI_IMPROVEMENT":
2545
+ return "Something looks off";
2546
+ case "PERFORMANCE":
2547
+ return "Something is slow";
2548
+ case "SECURITY":
2549
+ return "Report a security concern";
2118
2550
  case "QUESTION":
2119
2551
  return "Ask a question";
2120
2552
  case "OTHER":
@@ -2128,6 +2560,12 @@ function getPlaceholder(type, idx = 0, hasVoice = false) {
2128
2560
  return "What went wrong? Describe it or paste an error...";
2129
2561
  case "FEATURE_REQUEST":
2130
2562
  return "Describe the feature you'd like...";
2563
+ case "UI_IMPROVEMENT":
2564
+ return "What looks off? Describe the visual issue...";
2565
+ case "PERFORMANCE":
2566
+ return "What's slow? Describe when it happens...";
2567
+ case "SECURITY":
2568
+ return "Describe the security concern...";
2131
2569
  case "QUESTION":
2132
2570
  return "What would you like to know?";
2133
2571
  case "OTHER":
@@ -2144,7 +2582,7 @@ function getTypeIcon(type, color, size = 24) {
2144
2582
  };
2145
2583
  switch (type) {
2146
2584
  case "BUG":
2147
- return /* @__PURE__ */ jsx("svg", { ...props, children: /* @__PURE__ */ jsx(
2585
+ return /* @__PURE__ */ jsx2("svg", { ...props, children: /* @__PURE__ */ jsx2(
2148
2586
  "path",
2149
2587
  {
2150
2588
  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",
@@ -2154,7 +2592,7 @@ function getTypeIcon(type, color, size = 24) {
2154
2592
  }
2155
2593
  ) });
2156
2594
  case "FEATURE_REQUEST":
2157
- return /* @__PURE__ */ jsx("svg", { ...props, children: /* @__PURE__ */ jsx(
2595
+ return /* @__PURE__ */ jsx2("svg", { ...props, children: /* @__PURE__ */ jsx2(
2158
2596
  "path",
2159
2597
  {
2160
2598
  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",
@@ -2163,10 +2601,55 @@ function getTypeIcon(type, color, size = 24) {
2163
2601
  strokeLinejoin: "round"
2164
2602
  }
2165
2603
  ) });
2604
+ case "UI_IMPROVEMENT":
2605
+ return /* @__PURE__ */ jsxs2("svg", { ...props, children: [
2606
+ /* @__PURE__ */ jsx2(
2607
+ "rect",
2608
+ {
2609
+ x: "3",
2610
+ y: "3",
2611
+ width: "18",
2612
+ height: "18",
2613
+ rx: "2",
2614
+ stroke: color,
2615
+ strokeWidth: "1.5"
2616
+ }
2617
+ ),
2618
+ /* @__PURE__ */ jsx2(
2619
+ "path",
2620
+ {
2621
+ d: "M3 9h18M9 21V9",
2622
+ stroke: color,
2623
+ strokeWidth: "1.5",
2624
+ strokeLinecap: "round"
2625
+ }
2626
+ )
2627
+ ] });
2628
+ case "PERFORMANCE":
2629
+ return /* @__PURE__ */ jsx2("svg", { ...props, children: /* @__PURE__ */ jsx2(
2630
+ "path",
2631
+ {
2632
+ d: "M12 21a9 9 0 100-18 9 9 0 000 18zM12 12l4-4M12 7v.01",
2633
+ stroke: color,
2634
+ strokeWidth: "1.5",
2635
+ strokeLinecap: "round",
2636
+ strokeLinejoin: "round"
2637
+ }
2638
+ ) });
2639
+ case "SECURITY":
2640
+ return /* @__PURE__ */ jsx2("svg", { ...props, children: /* @__PURE__ */ jsx2(
2641
+ "path",
2642
+ {
2643
+ d: "M12 3l7 3v5c0 4.5-3 8.5-7 10-4-1.5-7-5.5-7-10V6l7-3z",
2644
+ stroke: color,
2645
+ strokeWidth: "1.5",
2646
+ strokeLinejoin: "round"
2647
+ }
2648
+ ) });
2166
2649
  case "QUESTION":
2167
- return /* @__PURE__ */ jsxs("svg", { ...props, children: [
2168
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", stroke: color, strokeWidth: "1.5" }),
2169
- /* @__PURE__ */ jsx(
2650
+ return /* @__PURE__ */ jsxs2("svg", { ...props, children: [
2651
+ /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "10", stroke: color, strokeWidth: "1.5" }),
2652
+ /* @__PURE__ */ jsx2(
2170
2653
  "path",
2171
2654
  {
2172
2655
  d: "M9.09 9a3 3 0 015.83 1c0 2-3 3-3 3M12 17h.01",
@@ -2178,7 +2661,7 @@ function getTypeIcon(type, color, size = 24) {
2178
2661
  )
2179
2662
  ] });
2180
2663
  case "OTHER":
2181
- return /* @__PURE__ */ jsx("svg", { ...props, children: /* @__PURE__ */ jsx(
2664
+ return /* @__PURE__ */ jsx2("svg", { ...props, children: /* @__PURE__ */ jsx2(
2182
2665
  "path",
2183
2666
  {
2184
2667
  d: "M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2v10z",
@@ -2191,7 +2674,7 @@ function getTypeIcon(type, color, size = 24) {
2191
2674
  }
2192
2675
 
2193
2676
  // src/provider.tsx
2194
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2677
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2195
2678
  var DEFAULT_BASE_URL2 = "https://glitchgrab.dev";
2196
2679
  var GlitchgrabContext = createContext(null);
2197
2680
  function useGlitchgrab() {
@@ -2215,13 +2698,13 @@ function GlitchgrabProviderInner({
2215
2698
  showSeverity,
2216
2699
  ignoreErrors
2217
2700
  }) {
2218
- const visitedPagesRef = useRef2([]);
2219
- useEffect2(() => {
2701
+ const visitedPagesRef = useRef3([]);
2702
+ useEffect3(() => {
2220
2703
  if (enableBreadcrumbs) {
2221
2704
  initBreadcrumbs(maxBreadcrumbs2);
2222
2705
  }
2223
2706
  }, [enableBreadcrumbs, maxBreadcrumbs2]);
2224
- useEffect2(() => {
2707
+ useEffect3(() => {
2225
2708
  try {
2226
2709
  if (typeof window === "undefined") return;
2227
2710
  const trackPage = () => {
@@ -2258,7 +2741,7 @@ function GlitchgrabProviderInner({
2258
2741
  } catch (e) {
2259
2742
  }
2260
2743
  }, []);
2261
- useEffect2(() => {
2744
+ useEffect3(() => {
2262
2745
  try {
2263
2746
  if (typeof window === "undefined") return;
2264
2747
  if (process.env.NODE_ENV === "development") return;
@@ -2455,7 +2938,7 @@ function GlitchgrabProviderInner({
2455
2938
  window.dispatchEvent(new CustomEvent("glitchgrab:open-report", { detail: options }));
2456
2939
  }
2457
2940
  }, []);
2458
- useEffect2(() => {
2941
+ useEffect3(() => {
2459
2942
  try {
2460
2943
  if (typeof window === "undefined") return;
2461
2944
  const handleKeyDown = (e) => {
@@ -2469,7 +2952,7 @@ function GlitchgrabProviderInner({
2469
2952
  } catch (e) {
2470
2953
  }
2471
2954
  }, [openReportDialog]);
2472
- return /* @__PURE__ */ jsxs2(
2955
+ return /* @__PURE__ */ jsxs3(
2473
2956
  GlitchgrabContext.Provider,
2474
2957
  {
2475
2958
  value: {
@@ -2482,7 +2965,7 @@ function GlitchgrabProviderInner({
2482
2965
  enhanceText: enhance
2483
2966
  },
2484
2967
  children: [
2485
- /* @__PURE__ */ jsx2(
2968
+ /* @__PURE__ */ jsx3(
2486
2969
  GlitchgrabErrorBoundary,
2487
2970
  {
2488
2971
  token,
@@ -2494,27 +2977,27 @@ function GlitchgrabProviderInner({
2494
2977
  children
2495
2978
  }
2496
2979
  ),
2497
- /* @__PURE__ */ jsx2(ReportDialog, { report, enhanceText: enhance, transcribeAudio: transcribe, types, showSeverity })
2980
+ /* @__PURE__ */ jsx3(ReportDialog, { report, enhanceText: enhance, transcribeAudio: transcribe, types, showSeverity })
2498
2981
  ]
2499
2982
  }
2500
2983
  );
2501
2984
  }
2502
2985
  function GlitchgrabProvider(props) {
2503
- if (!props.token) return /* @__PURE__ */ jsx2(Fragment2, { children: props.children });
2986
+ if (!props.token) return /* @__PURE__ */ jsx3(Fragment2, { children: props.children });
2504
2987
  const resolvedProps = {
2505
2988
  ...props,
2506
2989
  baseUrl: props.baseUrl || DEFAULT_BASE_URL2
2507
2990
  };
2508
2991
  try {
2509
- return /* @__PURE__ */ jsx2(GlitchgrabProviderInner, { ...resolvedProps });
2992
+ return /* @__PURE__ */ jsx3(GlitchgrabProviderInner, { ...resolvedProps });
2510
2993
  } catch (e) {
2511
- return /* @__PURE__ */ jsx2(Fragment2, { children: props.children });
2994
+ return /* @__PURE__ */ jsx3(Fragment2, { children: props.children });
2512
2995
  }
2513
2996
  }
2514
2997
 
2515
2998
  // src/report-button.tsx
2516
- import { useState as useState3 } from "react";
2517
- import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2999
+ import { useState as useState4 } from "react";
3000
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2518
3001
  function useGlitchgrabSafe() {
2519
3002
  try {
2520
3003
  return useGlitchgrab();
@@ -2529,7 +3012,7 @@ function ReportButton({
2529
3012
  children
2530
3013
  }) {
2531
3014
  var _a, _b;
2532
- const [capturing, setCapturing] = useState3(false);
3015
+ const [capturing, setCapturing] = useState4(false);
2533
3016
  const glitchgrab = useGlitchgrabSafe();
2534
3017
  if (!glitchgrab) return null;
2535
3018
  const handleClick = async () => {
@@ -2538,7 +3021,7 @@ function ReportButton({
2538
3021
  setCapturing(false);
2539
3022
  };
2540
3023
  if (children) {
2541
- return /* @__PURE__ */ jsx3(Fragment3, { children: children({ onClick: handleClick, capturing }) });
3024
+ return /* @__PURE__ */ jsx4(Fragment3, { children: children({ onClick: handleClick, capturing }) });
2542
3025
  }
2543
3026
  const isTop = (_a = position == null ? void 0 : position.startsWith("top")) != null ? _a : false;
2544
3027
  const isLeft = (_b = position == null ? void 0 : position.endsWith("left")) != null ? _b : false;
@@ -2546,7 +3029,7 @@ function ReportButton({
2546
3029
  ...isLeft ? { left: "16px" } : { right: "16px" },
2547
3030
  ...isTop ? { top: "16px" } : { bottom: "16px" }
2548
3031
  };
2549
- return /* @__PURE__ */ jsxs3(
3032
+ return /* @__PURE__ */ jsxs4(
2550
3033
  "button",
2551
3034
  {
2552
3035
  type: "button",
@@ -2581,7 +3064,7 @@ function ReportButton({
2581
3064
  },
2582
3065
  "aria-label": label,
2583
3066
  children: [
2584
- /* @__PURE__ */ jsx3(
3067
+ /* @__PURE__ */ jsx4(
2585
3068
  "svg",
2586
3069
  {
2587
3070
  width: "16",
@@ -2589,7 +3072,7 @@ function ReportButton({
2589
3072
  viewBox: "0 0 16 16",
2590
3073
  fill: "none",
2591
3074
  style: { flexShrink: 0 },
2592
- children: /* @__PURE__ */ jsx3(
3075
+ children: /* @__PURE__ */ jsx4(
2593
3076
  "path",
2594
3077
  {
2595
3078
  d: "M8 1C4.134 1 1 4.134 1 8s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm0 12.5a.75.75 0 110-1.5.75.75 0 010 1.5zm.75-3.5a.75.75 0 01-1.5 0V5a.75.75 0 011.5 0v5z",
@@ -2605,17 +3088,17 @@ function ReportButton({
2605
3088
  }
2606
3089
 
2607
3090
  // src/use-reports.ts
2608
- import { useState as useState4, useEffect as useEffect3, useCallback as useCallback2 } from "react";
3091
+ import { useState as useState5, useEffect as useEffect4, useCallback as useCallback2 } from "react";
2609
3092
  var BASE_URL = "https://glitchgrab.dev";
2610
3093
  function useGlitchgrabReports({
2611
3094
  token,
2612
3095
  userId,
2613
3096
  limit = 100
2614
3097
  }) {
2615
- const [reports, setReports] = useState4([]);
2616
- const [isLoading, setIsLoading] = useState4(true);
2617
- const [isFetching, setIsFetching] = useState4(false);
2618
- const [error, setError] = useState4(null);
3098
+ const [reports, setReports] = useState5([]);
3099
+ const [isLoading, setIsLoading] = useState5(true);
3100
+ const [isFetching, setIsFetching] = useState5(false);
3101
+ const [error, setError] = useState5(null);
2619
3102
  const fetchReports = useCallback2(async () => {
2620
3103
  var _a, _b;
2621
3104
  if (!token || !userId) {
@@ -2642,7 +3125,7 @@ function useGlitchgrabReports({
2642
3125
  setIsFetching(false);
2643
3126
  }
2644
3127
  }, [token, userId, limit]);
2645
- useEffect3(() => {
3128
+ useEffect4(() => {
2646
3129
  fetchReports();
2647
3130
  }, [fetchReports]);
2648
3131
  return { reports, isLoading, isFetching, error, refetch: fetchReports };
@@ -2679,8 +3162,8 @@ function useGlitchgrabActions({
2679
3162
  onSuccess,
2680
3163
  onError
2681
3164
  }) {
2682
- const [isPending, setIsPending] = useState4(false);
2683
- const [error, setError] = useState4(null);
3165
+ const [isPending, setIsPending] = useState5(false);
3166
+ const [error, setError] = useState5(null);
2684
3167
  const run = useCallback2(
2685
3168
  async (reportId, body) => {
2686
3169
  setIsPending(true);