glitchgrab 1.0.1 → 1.1.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
@@ -1,5 +1,5 @@
1
- "use client";
2
1
  "use strict";
2
+ "use client";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -47,10 +47,10 @@ __export(index_exports, {
47
47
  module.exports = __toCommonJS(index_exports);
48
48
 
49
49
  // src/provider.tsx
50
- var import_react2 = require("react");
50
+ var import_react = require("react");
51
51
 
52
52
  // src/error-boundary.tsx
53
- var import_react = __toESM(require("react"));
53
+ var React = __toESM(require("react"));
54
54
 
55
55
  // src/breadcrumbs.ts
56
56
  var MAX_DEFAULT = 50;
@@ -310,7 +310,7 @@ async function sendReport(payload, baseUrl) {
310
310
  }
311
311
 
312
312
  // src/error-boundary.tsx
313
- var GlitchgrabErrorBoundary = class extends import_react.default.Component {
313
+ var GlitchgrabErrorBoundary = class extends React.Component {
314
314
  constructor(props) {
315
315
  super(props);
316
316
  this.state = { hasError: false };
@@ -359,9 +359,9 @@ var GlitchgrabErrorBoundary = class extends import_react.default.Component {
359
359
  // src/provider.tsx
360
360
  var import_jsx_runtime = require("react/jsx-runtime");
361
361
  var DEFAULT_BASE_URL2 = "https://glitchgrab.dev";
362
- var GlitchgrabContext = (0, import_react2.createContext)(null);
362
+ var GlitchgrabContext = (0, import_react.createContext)(null);
363
363
  function useGlitchgrab() {
364
- const ctx = (0, import_react2.useContext)(GlitchgrabContext);
364
+ const ctx = (0, import_react.useContext)(GlitchgrabContext);
365
365
  if (!ctx) {
366
366
  throw new Error("useGlitchgrab must be used within a GlitchgrabProvider");
367
367
  }
@@ -369,6 +369,7 @@ function useGlitchgrab() {
369
369
  }
370
370
  function GlitchgrabProviderInner({
371
371
  token,
372
+ session,
372
373
  baseUrl,
373
374
  onError,
374
375
  onReportSent,
@@ -377,13 +378,13 @@ function GlitchgrabProviderInner({
377
378
  children,
378
379
  fallback
379
380
  }) {
380
- const visitedPagesRef = (0, import_react2.useRef)([]);
381
- (0, import_react2.useEffect)(() => {
381
+ const visitedPagesRef = (0, import_react.useRef)([]);
382
+ (0, import_react.useEffect)(() => {
382
383
  if (enableBreadcrumbs) {
383
384
  initBreadcrumbs(maxBreadcrumbs2);
384
385
  }
385
386
  }, [enableBreadcrumbs, maxBreadcrumbs2]);
386
- (0, import_react2.useEffect)(() => {
387
+ (0, import_react.useEffect)(() => {
387
388
  try {
388
389
  if (typeof window === "undefined") return;
389
390
  const trackPage = () => {
@@ -420,9 +421,10 @@ function GlitchgrabProviderInner({
420
421
  } catch (e) {
421
422
  }
422
423
  }, []);
423
- (0, import_react2.useEffect)(() => {
424
+ (0, import_react.useEffect)(() => {
424
425
  try {
425
426
  if (typeof window === "undefined") return;
427
+ if (process.env.NODE_ENV === "development") return;
426
428
  const handleError = (event) => {
427
429
  var _a, _b, _c, _d, _e;
428
430
  try {
@@ -442,7 +444,10 @@ function GlitchgrabProviderInner({
442
444
  visitedPages: JSON.stringify(context.visitedPages),
443
445
  filename: (_c = event.filename) != null ? _c : "",
444
446
  lineno: String((_d = event.lineno) != null ? _d : ""),
445
- colno: String((_e = event.colno) != null ? _e : "")
447
+ colno: String((_e = event.colno) != null ? _e : ""),
448
+ ...(session == null ? void 0 : session.userId) ? { sessionUserId: session.userId } : {},
449
+ ...(session == null ? void 0 : session.name) ? { sessionUserName: String(session.name) } : {},
450
+ ...(session == null ? void 0 : session.email) ? { sessionUserEmail: String(session.email) } : {}
446
451
  }
447
452
  };
448
453
  sendReport(payload, baseUrl).then((result) => {
@@ -470,7 +475,10 @@ function GlitchgrabProviderInner({
470
475
  metadata: {
471
476
  timestamp: context.timestamp,
472
477
  visitedPages: JSON.stringify(context.visitedPages),
473
- type: "unhandledrejection"
478
+ type: "unhandledrejection",
479
+ ...(session == null ? void 0 : session.userId) ? { sessionUserId: session.userId } : {},
480
+ ...(session == null ? void 0 : session.name) ? { sessionUserName: String(session.name) } : {},
481
+ ...(session == null ? void 0 : session.email) ? { sessionUserEmail: String(session.email) } : {}
474
482
  }
475
483
  };
476
484
  sendReport(payload, baseUrl).then((result) => {
@@ -489,7 +497,7 @@ function GlitchgrabProviderInner({
489
497
  } catch (e) {
490
498
  }
491
499
  }, [token, baseUrl, onError, onReportSent]);
492
- const report = (0, import_react2.useCallback)(
500
+ const report = (0, import_react.useCallback)(
493
501
  async (type, description, metadata) => {
494
502
  var _a;
495
503
  try {
@@ -506,6 +514,10 @@ function GlitchgrabProviderInner({
506
514
  metadata: {
507
515
  timestamp: context.timestamp,
508
516
  visitedPages: JSON.stringify(context.visitedPages),
517
+ ...(session == null ? void 0 : session.userId) ? { sessionUserId: session.userId } : {},
518
+ ...(session == null ? void 0 : session.name) ? { sessionUserName: String(session.name) } : {},
519
+ ...(session == null ? void 0 : session.email) ? { sessionUserEmail: String(session.email) } : {},
520
+ ...(session == null ? void 0 : session.phone) ? { sessionUserPhone: String(session.phone) } : {},
509
521
  ...metadata
510
522
  }
511
523
  };
@@ -518,11 +530,11 @@ function GlitchgrabProviderInner({
518
530
  },
519
531
  [token, baseUrl, onReportSent]
520
532
  );
521
- const reportBug = (0, import_react2.useCallback)(
533
+ const reportBug = (0, import_react.useCallback)(
522
534
  (description, metadata) => report("BUG", description, metadata),
523
535
  [report]
524
536
  );
525
- const addBreadcrumb2 = (0, import_react2.useCallback)(
537
+ const addBreadcrumb2 = (0, import_react.useCallback)(
526
538
  (message, data) => {
527
539
  addBreadcrumb("custom", message, data);
528
540
  },
@@ -553,47 +565,103 @@ function GlitchgrabProviderInner({
553
565
  );
554
566
  }
555
567
  function GlitchgrabProvider(props) {
568
+ if (!props.token) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: props.children });
569
+ const resolvedProps = {
570
+ ...props,
571
+ baseUrl: props.baseUrl || (typeof window !== "undefined" ? window.location.origin : DEFAULT_BASE_URL2)
572
+ };
556
573
  try {
557
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GlitchgrabProviderInner, { ...props });
574
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GlitchgrabProviderInner, { ...resolvedProps });
558
575
  } catch (e) {
559
576
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: props.children });
560
577
  }
561
578
  }
562
579
 
563
580
  // src/report-button.tsx
564
- var import_react3 = require("react");
581
+ var import_react2 = require("react");
565
582
  var import_jsx_runtime2 = require("react/jsx-runtime");
566
583
  function ReportButton({
567
584
  position = "bottom-right",
568
585
  label = "Report Bug",
569
- className
586
+ className,
587
+ children
570
588
  }) {
571
- const [isOpen, setIsOpen] = (0, import_react3.useState)(false);
572
- const [description, setDescription] = (0, import_react3.useState)("");
573
- const [isSubmitting, setIsSubmitting] = (0, import_react3.useState)(false);
574
- const [submitted, setSubmitted] = (0, import_react3.useState)(false);
575
- const modalRef = (0, import_react3.useRef)(null);
589
+ var _a, _b;
590
+ const [capturing, setCapturing] = (0, import_react2.useState)(false);
591
+ const [isOpen, setIsOpen] = (0, import_react2.useState)(false);
592
+ const [description, setDescription] = (0, import_react2.useState)("");
593
+ const [isSubmitting, setIsSubmitting] = (0, import_react2.useState)(false);
594
+ const [submitted, setSubmitted] = (0, import_react2.useState)(false);
595
+ const [screenshot, setScreenshot] = (0, import_react2.useState)(null);
596
+ const [previewOpen, setPreviewOpen] = (0, import_react2.useState)(false);
597
+ const fileInputRef = (0, import_react2.useRef)(null);
598
+ const modalRef = (0, import_react2.useRef)(null);
576
599
  const { reportBug } = useGlitchgrab();
577
- (0, import_react3.useEffect)(() => {
600
+ const handleFileUpload = (e) => {
601
+ var _a2;
602
+ const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
603
+ if (!file) return;
604
+ const reader = new FileReader();
605
+ reader.onload = () => {
606
+ setScreenshot(reader.result);
607
+ };
608
+ reader.readAsDataURL(file);
609
+ e.target.value = "";
610
+ };
611
+ const retakeScreenshot = async () => {
612
+ setPreviewOpen(false);
613
+ setIsOpen(false);
614
+ setScreenshot(null);
615
+ await new Promise((r) => setTimeout(r, 300));
578
616
  try {
579
- if (!isOpen) return;
580
- const handleClickOutside = (event) => {
581
- if (modalRef.current && !modalRef.current.contains(event.target)) {
582
- setIsOpen(false);
583
- }
584
- };
585
- document.addEventListener("mousedown", handleClickOutside);
586
- return () => document.removeEventListener("mousedown", handleClickOutside);
617
+ const { default: html2canvas } = await import("html2canvas-pro");
618
+ const canvas = await html2canvas(document.body, {
619
+ scale: 0.5,
620
+ logging: false,
621
+ useCORS: true,
622
+ allowTaint: true
623
+ });
624
+ setScreenshot(canvas.toDataURL("image/jpeg", 0.6));
625
+ } catch (e) {
626
+ }
627
+ setIsOpen(true);
628
+ };
629
+ const handleOpen = async () => {
630
+ setCapturing(true);
631
+ setSubmitted(false);
632
+ try {
633
+ const { default: html2canvas } = await import("html2canvas-pro");
634
+ const canvas = await html2canvas(document.body, {
635
+ scale: 0.5,
636
+ logging: false,
637
+ useCORS: true,
638
+ allowTaint: true
639
+ });
640
+ setScreenshot(canvas.toDataURL("image/jpeg", 0.6));
587
641
  } catch (e) {
588
642
  }
589
- }, [isOpen]);
643
+ setCapturing(false);
644
+ setIsOpen(true);
645
+ };
646
+ (0, import_react2.useEffect)(() => {
647
+ if (!isOpen) return;
648
+ const handleEsc = (e) => {
649
+ if (e.key === "Escape") {
650
+ if (previewOpen) setPreviewOpen(false);
651
+ else setIsOpen(false);
652
+ }
653
+ };
654
+ document.addEventListener("keydown", handleEsc);
655
+ return () => document.removeEventListener("keydown", handleEsc);
656
+ }, [isOpen, previewOpen]);
590
657
  const handleSubmit = () => {
591
658
  try {
592
659
  if (!description.trim() || isSubmitting) return;
593
660
  setIsSubmitting(true);
594
- reportBug(description.trim());
661
+ reportBug(description.trim(), screenshot ? { screenshot } : void 0);
595
662
  setSubmitted(true);
596
663
  setDescription("");
664
+ setScreenshot(null);
597
665
  setIsSubmitting(false);
598
666
  setTimeout(() => {
599
667
  setSubmitted(false);
@@ -603,206 +671,386 @@ function ReportButton({
603
671
  setIsSubmitting(false);
604
672
  }
605
673
  };
606
- const positionStyles = position === "bottom-left" ? { left: "16px", bottom: "16px" } : { right: "16px", bottom: "16px" };
607
- const modalPositionStyles = position === "bottom-left" ? { left: "16px", bottom: "64px" } : { right: "16px", bottom: "64px" };
674
+ const isTop = (_a = position == null ? void 0 : position.startsWith("top")) != null ? _a : false;
675
+ const isLeft = (_b = position == null ? void 0 : position.endsWith("left")) != null ? _b : false;
676
+ const modalPositionStyles = children ? {} : {
677
+ ...isLeft ? { left: "16px" } : { right: "16px" },
678
+ ...isTop ? { top: "64px" } : { bottom: "64px" }
679
+ };
608
680
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
609
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
610
- "button",
681
+ children ? children({ onClick: handleOpen, capturing }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
682
+ DefaultTrigger,
611
683
  {
612
- type: "button",
613
- onClick: () => {
614
- setIsOpen(!isOpen);
615
- setSubmitted(false);
616
- },
684
+ onClick: handleOpen,
685
+ capturing,
686
+ label,
617
687
  className,
688
+ position,
689
+ isLeft,
690
+ isTop
691
+ }
692
+ ),
693
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
694
+ "div",
695
+ {
618
696
  style: {
619
697
  position: "fixed",
620
- ...positionStyles,
698
+ inset: 0,
621
699
  zIndex: 99999,
622
- padding: "10px 18px",
623
- borderRadius: "24px",
624
- border: "none",
625
- backgroundColor: "#18181b",
626
- color: "#fafafa",
627
- fontSize: "14px",
628
- fontWeight: 500,
629
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
630
- cursor: "pointer",
631
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)",
632
- transition: "transform 0.15s ease, box-shadow 0.15s ease",
633
700
  display: "flex",
634
701
  alignItems: "center",
635
- gap: "6px"
702
+ justifyContent: "center",
703
+ backgroundColor: "rgba(0,0,0,0.5)"
636
704
  },
637
- onMouseEnter: (e) => {
638
- e.target.style.transform = "scale(1.05)";
639
- },
640
- onMouseLeave: (e) => {
641
- e.target.style.transform = "scale(1)";
705
+ onClick: () => {
706
+ if (!previewOpen) setIsOpen(false);
642
707
  },
643
- "aria-label": label,
644
- children: [
645
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
646
- "svg",
647
- {
648
- width: "16",
649
- height: "16",
650
- viewBox: "0 0 16 16",
651
- fill: "none",
652
- style: { flexShrink: 0 },
653
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
654
- "path",
708
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
709
+ "div",
710
+ {
711
+ ref: modalRef,
712
+ onClick: (e) => e.stopPropagation(),
713
+ style: {
714
+ position: children ? "relative" : "fixed",
715
+ ...modalPositionStyles,
716
+ zIndex: 1e5,
717
+ width: "340px",
718
+ maxWidth: "calc(100% - 32px)",
719
+ backgroundColor: "#1c1c1e",
720
+ borderRadius: "12px",
721
+ boxShadow: "0 20px 60px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.3)",
722
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
723
+ overflow: "hidden",
724
+ color: "#fafafa"
725
+ },
726
+ children: [
727
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
728
+ "div",
655
729
  {
656
- 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",
657
- fill: "currentColor"
730
+ style: {
731
+ padding: "16px 16px 12px",
732
+ borderBottom: "1px solid #2c2c2e"
733
+ },
734
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
735
+ "div",
736
+ {
737
+ style: {
738
+ display: "flex",
739
+ justifyContent: "space-between",
740
+ alignItems: "center"
741
+ },
742
+ children: [
743
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
744
+ "span",
745
+ {
746
+ style: {
747
+ fontSize: "15px",
748
+ fontWeight: 600,
749
+ color: "#fafafa"
750
+ },
751
+ children: "Report a Bug"
752
+ }
753
+ ),
754
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
755
+ "button",
756
+ {
757
+ type: "button",
758
+ onClick: () => setIsOpen(false),
759
+ style: {
760
+ background: "none",
761
+ border: "none",
762
+ cursor: "pointer",
763
+ padding: "4px",
764
+ color: "#a1a1aa",
765
+ fontSize: "18px",
766
+ lineHeight: 1
767
+ },
768
+ "aria-label": "Close",
769
+ children: "\xD7"
770
+ }
771
+ )
772
+ ]
773
+ }
774
+ )
775
+ }
776
+ ),
777
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "16px" }, children: submitted ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
778
+ "div",
779
+ {
780
+ style: {
781
+ textAlign: "center",
782
+ padding: "20px 0",
783
+ color: "#22d3ee",
784
+ fontSize: "14px",
785
+ fontWeight: 500
786
+ },
787
+ children: "Bug report sent. Thank you!"
788
+ }
789
+ ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
790
+ screenshot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "10px", position: "relative" }, children: [
791
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
792
+ "img",
793
+ {
794
+ src: screenshot,
795
+ alt: "Page screenshot",
796
+ onClick: () => setPreviewOpen(true),
797
+ style: {
798
+ width: "100%",
799
+ borderRadius: "6px",
800
+ border: "1px solid #2c2c2e",
801
+ maxHeight: "120px",
802
+ objectFit: "cover",
803
+ objectPosition: "top",
804
+ cursor: "pointer"
805
+ }
806
+ }
807
+ ),
808
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
809
+ "button",
810
+ {
811
+ type: "button",
812
+ onClick: () => setScreenshot(null),
813
+ style: {
814
+ position: "absolute",
815
+ top: "4px",
816
+ right: "4px",
817
+ background: "rgba(0,0,0,0.6)",
818
+ border: "none",
819
+ borderRadius: "50%",
820
+ color: "#fff",
821
+ width: "20px",
822
+ height: "20px",
823
+ fontSize: "12px",
824
+ cursor: "pointer",
825
+ display: "flex",
826
+ alignItems: "center",
827
+ justifyContent: "center",
828
+ lineHeight: 1
829
+ },
830
+ "aria-label": "Remove screenshot",
831
+ children: "\xD7"
832
+ }
833
+ ),
834
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
835
+ "div",
836
+ {
837
+ style: {
838
+ position: "absolute",
839
+ bottom: "4px",
840
+ left: "6px",
841
+ right: "6px",
842
+ display: "flex",
843
+ justifyContent: "space-between",
844
+ alignItems: "center"
845
+ },
846
+ children: [
847
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
848
+ "span",
849
+ {
850
+ style: {
851
+ background: "rgba(0,0,0,0.6)",
852
+ color: "#fff",
853
+ fontSize: "10px",
854
+ padding: "2px 6px",
855
+ borderRadius: "4px"
856
+ },
857
+ children: [
858
+ "Screenshot (",
859
+ Math.round(screenshot.length * 0.75 / 1024),
860
+ "KB) \u2014 click to preview"
861
+ ]
862
+ }
863
+ ),
864
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "4px" }, children: [
865
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
866
+ "button",
867
+ {
868
+ type: "button",
869
+ onClick: () => {
870
+ var _a2;
871
+ return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
872
+ },
873
+ style: {
874
+ background: "rgba(0,0,0,0.6)",
875
+ color: "#22d3ee",
876
+ fontSize: "10px",
877
+ padding: "2px 6px",
878
+ borderRadius: "4px",
879
+ border: "none",
880
+ cursor: "pointer"
881
+ },
882
+ children: "Upload"
883
+ }
884
+ ),
885
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
886
+ "button",
887
+ {
888
+ type: "button",
889
+ onClick: retakeScreenshot,
890
+ style: {
891
+ background: "rgba(0,0,0,0.6)",
892
+ color: "#22d3ee",
893
+ fontSize: "10px",
894
+ padding: "2px 6px",
895
+ borderRadius: "4px",
896
+ border: "none",
897
+ cursor: "pointer"
898
+ },
899
+ children: "Retake"
900
+ }
901
+ )
902
+ ] })
903
+ ]
904
+ }
905
+ )
906
+ ] }),
907
+ !screenshot && !submitted && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
908
+ "button",
909
+ {
910
+ type: "button",
911
+ onClick: () => {
912
+ var _a2;
913
+ return (_a2 = fileInputRef.current) == null ? void 0 : _a2.click();
914
+ },
915
+ style: {
916
+ marginBottom: "10px",
917
+ padding: "10px",
918
+ borderRadius: "6px",
919
+ border: "1px dashed #3f3f46",
920
+ textAlign: "center",
921
+ fontSize: "11px",
922
+ color: "#71717a",
923
+ width: "100%",
924
+ background: "none",
925
+ cursor: "pointer"
926
+ },
927
+ children: "Click to upload a screenshot"
928
+ }
929
+ ),
930
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
931
+ "textarea",
932
+ {
933
+ value: description,
934
+ onChange: (e) => setDescription(e.target.value),
935
+ placeholder: "Describe what went wrong...",
936
+ style: {
937
+ width: "100%",
938
+ minHeight: "100px",
939
+ padding: "10px 12px",
940
+ borderRadius: "8px",
941
+ border: "1px solid #3f3f46",
942
+ fontSize: "14px",
943
+ fontFamily: "inherit",
944
+ resize: "vertical",
945
+ outline: "none",
946
+ boxSizing: "border-box",
947
+ color: "#fafafa",
948
+ backgroundColor: "#27272a"
949
+ },
950
+ onFocus: (e) => {
951
+ e.target.style.borderColor = "#22d3ee";
952
+ },
953
+ onBlur: (e) => {
954
+ e.target.style.borderColor = "#3f3f46";
955
+ },
956
+ autoFocus: true
957
+ }
958
+ ),
959
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
960
+ "button",
961
+ {
962
+ type: "button",
963
+ onClick: handleSubmit,
964
+ disabled: !description.trim() || isSubmitting,
965
+ style: {
966
+ marginTop: "12px",
967
+ width: "100%",
968
+ padding: "10px",
969
+ borderRadius: "8px",
970
+ border: "none",
971
+ backgroundColor: !description.trim() || isSubmitting ? "#3f3f46" : "#22d3ee",
972
+ color: !description.trim() || isSubmitting ? "#71717a" : "#09090b",
973
+ fontSize: "14px",
974
+ fontWeight: 600,
975
+ cursor: !description.trim() || isSubmitting ? "not-allowed" : "pointer",
976
+ fontFamily: "inherit",
977
+ transition: "background-color 0.15s ease"
978
+ },
979
+ children: isSubmitting ? "Sending..." : "Send Report"
980
+ }
981
+ )
982
+ ] }) }),
983
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
984
+ "div",
985
+ {
986
+ style: {
987
+ padding: "8px 16px 10px",
988
+ borderTop: "1px solid #2c2c2e",
989
+ textAlign: "center"
990
+ },
991
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "11px", color: "#52525b" }, children: "Powered by Glitchgrab" })
658
992
  }
659
993
  )
660
- }
661
- ),
662
- label
663
- ]
994
+ ]
995
+ }
996
+ )
664
997
  }
665
998
  ),
666
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
999
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1000
+ "input",
1001
+ {
1002
+ ref: fileInputRef,
1003
+ type: "file",
1004
+ accept: "image/*",
1005
+ onChange: handleFileUpload,
1006
+ style: { display: "none" }
1007
+ }
1008
+ ),
1009
+ previewOpen && screenshot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
667
1010
  "div",
668
1011
  {
669
- ref: modalRef,
670
1012
  style: {
671
1013
  position: "fixed",
672
- ...modalPositionStyles,
673
- zIndex: 1e5,
674
- width: "320px",
675
- backgroundColor: "#ffffff",
676
- borderRadius: "12px",
677
- boxShadow: "0 20px 60px rgba(0, 0, 0, 0.15), 0 4px 16px rgba(0, 0, 0, 0.1)",
678
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
679
- overflow: "hidden"
1014
+ inset: 0,
1015
+ zIndex: 2e5,
1016
+ backgroundColor: "rgba(0,0,0,0.85)",
1017
+ display: "flex",
1018
+ flexDirection: "column",
1019
+ alignItems: "center",
1020
+ justifyContent: "center",
1021
+ padding: "16px",
1022
+ cursor: "pointer"
1023
+ },
1024
+ onClick: (e) => {
1025
+ e.stopPropagation();
1026
+ setPreviewOpen(false);
680
1027
  },
1028
+ onMouseDown: (e) => e.stopPropagation(),
681
1029
  children: [
682
1030
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
683
- "div",
1031
+ "img",
684
1032
  {
1033
+ src: screenshot,
1034
+ alt: "Screenshot preview",
1035
+ onClick: (e) => e.stopPropagation(),
685
1036
  style: {
686
- padding: "16px 16px 12px",
687
- borderBottom: "1px solid #e4e4e7"
688
- },
689
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
690
- "div",
691
- {
692
- style: {
693
- display: "flex",
694
- justifyContent: "space-between",
695
- alignItems: "center"
696
- },
697
- children: [
698
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
699
- "span",
700
- {
701
- style: {
702
- fontSize: "15px",
703
- fontWeight: 600,
704
- color: "#18181b"
705
- },
706
- children: "Report a Bug"
707
- }
708
- ),
709
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
710
- "button",
711
- {
712
- type: "button",
713
- onClick: () => setIsOpen(false),
714
- style: {
715
- background: "none",
716
- border: "none",
717
- cursor: "pointer",
718
- padding: "4px",
719
- color: "#71717a",
720
- fontSize: "18px",
721
- lineHeight: 1
722
- },
723
- "aria-label": "Close",
724
- children: "\xD7"
725
- }
726
- )
727
- ]
728
- }
729
- )
1037
+ maxWidth: "100%",
1038
+ maxHeight: "calc(100vh - 80px)",
1039
+ borderRadius: "8px",
1040
+ objectFit: "contain",
1041
+ cursor: "default"
1042
+ }
730
1043
  }
731
1044
  ),
732
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "16px" }, children: submitted ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
733
- "div",
734
- {
735
- style: {
736
- textAlign: "center",
737
- padding: "20px 0",
738
- color: "#16a34a",
739
- fontSize: "14px",
740
- fontWeight: 500
741
- },
742
- children: "Bug report sent. Thank you!"
743
- }
744
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
745
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
746
- "textarea",
747
- {
748
- value: description,
749
- onChange: (e) => setDescription(e.target.value),
750
- placeholder: "Describe what went wrong...",
751
- style: {
752
- width: "100%",
753
- minHeight: "100px",
754
- padding: "10px 12px",
755
- borderRadius: "8px",
756
- border: "1px solid #d4d4d8",
757
- fontSize: "14px",
758
- fontFamily: "inherit",
759
- resize: "vertical",
760
- outline: "none",
761
- boxSizing: "border-box",
762
- color: "#18181b",
763
- backgroundColor: "#fafafa"
764
- },
765
- onFocus: (e) => {
766
- e.target.style.borderColor = "#18181b";
767
- },
768
- onBlur: (e) => {
769
- e.target.style.borderColor = "#d4d4d8";
770
- }
771
- }
772
- ),
773
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
774
- "button",
775
- {
776
- type: "button",
777
- onClick: handleSubmit,
778
- disabled: !description.trim() || isSubmitting,
779
- style: {
780
- marginTop: "12px",
781
- width: "100%",
782
- padding: "10px",
783
- borderRadius: "8px",
784
- border: "none",
785
- backgroundColor: !description.trim() || isSubmitting ? "#a1a1aa" : "#18181b",
786
- color: "#fafafa",
787
- fontSize: "14px",
788
- fontWeight: 500,
789
- cursor: !description.trim() || isSubmitting ? "not-allowed" : "pointer",
790
- fontFamily: "inherit",
791
- transition: "background-color 0.15s ease"
792
- },
793
- children: isSubmitting ? "Sending..." : "Send Report"
794
- }
795
- )
796
- ] }) }),
797
1045
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
798
- "div",
1046
+ "span",
799
1047
  {
800
1048
  style: {
801
- padding: "8px 16px 10px",
802
- borderTop: "1px solid #e4e4e7",
803
- textAlign: "center"
1049
+ marginTop: "12px",
1050
+ color: "#a1a1aa",
1051
+ fontSize: "12px"
804
1052
  },
805
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: "11px", color: "#a1a1aa" }, children: "Powered by Glitchgrab" })
1053
+ children: "Click outside to close"
806
1054
  }
807
1055
  )
808
1056
  ]
@@ -810,6 +1058,76 @@ function ReportButton({
810
1058
  )
811
1059
  ] });
812
1060
  }
1061
+ function DefaultTrigger({
1062
+ onClick,
1063
+ capturing,
1064
+ label,
1065
+ className,
1066
+ position,
1067
+ isLeft,
1068
+ isTop
1069
+ }) {
1070
+ const positionStyles = {
1071
+ ...isLeft ? { left: "16px" } : { right: "16px" },
1072
+ ...isTop ? { top: "16px" } : { bottom: "16px" }
1073
+ };
1074
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1075
+ "button",
1076
+ {
1077
+ type: "button",
1078
+ onClick,
1079
+ disabled: capturing,
1080
+ className,
1081
+ style: {
1082
+ position: "fixed",
1083
+ ...positionStyles,
1084
+ zIndex: 99999,
1085
+ padding: "10px 18px",
1086
+ borderRadius: "24px",
1087
+ border: "none",
1088
+ backgroundColor: "#18181b",
1089
+ color: "#fafafa",
1090
+ fontSize: "14px",
1091
+ fontWeight: 500,
1092
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1093
+ cursor: capturing ? "wait" : "pointer",
1094
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.1)",
1095
+ transition: "transform 0.15s ease, box-shadow 0.15s ease",
1096
+ display: "flex",
1097
+ alignItems: "center",
1098
+ gap: "6px",
1099
+ opacity: capturing ? 0.7 : 1
1100
+ },
1101
+ onMouseEnter: (e) => {
1102
+ e.target.style.transform = "scale(1.05)";
1103
+ },
1104
+ onMouseLeave: (e) => {
1105
+ e.target.style.transform = "scale(1)";
1106
+ },
1107
+ "aria-label": label,
1108
+ children: [
1109
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1110
+ "svg",
1111
+ {
1112
+ width: "16",
1113
+ height: "16",
1114
+ viewBox: "0 0 16 16",
1115
+ fill: "none",
1116
+ style: { flexShrink: 0 },
1117
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1118
+ "path",
1119
+ {
1120
+ 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",
1121
+ fill: "currentColor"
1122
+ }
1123
+ )
1124
+ }
1125
+ ),
1126
+ capturing ? "Capturing..." : label
1127
+ ]
1128
+ }
1129
+ );
1130
+ }
813
1131
  // Annotate the CommonJS export names for ESM import in node:
814
1132
  0 && (module.exports = {
815
1133
  GlitchgrabErrorBoundary,