bug-widget-library 0.0.0-stage → 0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug-widget-library.js","names":["_Fragment","CircleIcon","_Fragment","KonvaImage","Circle","_Fragment","html2canvas","Circle$1","getProjectLabel","projectUrl","Form","uiSettings","isLeft","pos","position","reportTitle","setReportTitle","useState","description","setDescription","isSubmitting","setIsSubmitting","isSuccess","setIsSuccess","submitError","setSubmitError","errors","setErrors","previewImage","setPreviewImage","projectLabel","validate","errs","Fragment","onClose","isOpen","title","primaryColor","Sparkles","subtitle","X","CheckCircle2","screenshots","e","onSubmitReport","err","prev","placeholderTitle","AlertCircle","placeholderDescription","s","idx","Eye","onEditScreenshot","Edit3","onDeleteScreenshot","Trash2","onTriggerScreenshot","Camera","Loader2","PRESET_COLORS","STROKE_WIDTHS","KonvaEditor","containerRef","useRef","stageRef","transformerRef","image","setImage","scale","setScale","stageDimensions","setStageDimensions","tool","setTool","color","setColor","strokeWidth","setStrokeWidth","selectedId","setSelectedId","shapes","setShapes","draftShape","setDraftShape","isDrawing","setIsDrawing","startPoint","setStartPoint","history","setHistory","historyStep","setHistoryStep","img","imageSrc","updateDimensions","useCallback","availWidth","availHeight","fitScale","useEffect","selectedNode","pushHistory","newHistory","newShapes","handleUndo","newStep","handleRedo","handleClearAll","handleDeleteSelected","handleKeyDown","handlePointerDown","stage","pointer","x","y","clickedNode","shapeId","id","newLine","handlePointerMove","rx","ry","rw","rh","radius","handlePointerUp","isValid","x1","y1","x2","y2","nextShapes","handleTransformEnd","node","targetShape","scaleX","scaleY","updated","handleDragEnd","Undo2","Redo2","onCancel","onSave","Check","MousePointer","Pencil","Eraser","Square","Circle","ArrowUpRight","c","Palette","sw","Stage","Layer","Image","isSelectable","shape","Line","next","Rect","Arrow","Transformer","newBox","oldBox","Widget","controlledIsOpen","internalIsOpen","setInternalIsOpen","setOpen","open","onToggle","setScreenshots","isCapturing","setIsCapturing","isEditorOpen","setIsEditorOpen","editingScreenshot","setEditingScreenshot","getPositionClasses","sizeClasses","size","buttonSize","className","buttonIcon","Bug","buttonText","resolve","dataUrl","element","item","onSubmit","reportData","onSuccess","error","onError","newItem","editedDataUrl"],"sources":["../src/components/Form.tsx","../src/components/KonvaEditor.tsx","../src/components/Widget.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport {\n Camera,\n X,\n Trash2,\n Edit3,\n Eye,\n CheckCircle2,\n AlertCircle,\n Loader2,\n Sparkles,\n} from 'lucide-react';\nimport type {\n BugReportData,\n ScreenshotItem,\n WidgetUiSettings,\n WidgetPosition,\n} from '../types';\n\ninterface FormProps {\n projectUrl: string;\n isOpen: boolean;\n onClose: () => void;\n uiSettings?: WidgetUiSettings;\n screenshots: ScreenshotItem[];\n onTriggerScreenshot: () => void;\n onEditScreenshot: (screenshot: ScreenshotItem) => void;\n onDeleteScreenshot: (id: string) => void;\n onSubmitReport: (data: BugReportData) => Promise<void> | void;\n}\n\nfunction getProjectLabel(projectUrl: string): string {\n try {\n return new URL(projectUrl).hostname;\n } catch {\n return 'project';\n }\n}\n\nexport const Form: React.FC<FormProps> = ({\n projectUrl,\n isOpen,\n onClose,\n uiSettings = {},\n screenshots,\n onTriggerScreenshot,\n onEditScreenshot,\n onDeleteScreenshot,\n onSubmitReport,\n}) => {\n const {\n position = 'bottom-right',\n primaryColor = '#2563eb',\n title = 'Report a Bug',\n subtitle = 'Found an issue? Let us know with details and screenshots.',\n placeholderTitle = 'e.g. Broken checkout button on cart page',\n placeholderDescription = 'Describe what happened, steps to reproduce, and expected result...',\n } = uiSettings;\n\n const isLeftPosition = (pos: WidgetPosition) =>\n pos === 'bottom-left' || pos === 'top-left' || pos === 'left';\n\n const isLeft = isLeftPosition(position);\n\n // Form input states\n const [reportTitle, setReportTitle] = useState('');\n const [description, setDescription] = useState('');\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isSuccess, setIsSuccess] = useState(false);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [errors, setErrors] = useState<{ title?: string; description?: string }>({});\n const [previewImage, setPreviewImage] = useState<string | null>(null);\n const projectLabel = getProjectLabel(projectUrl);\n\n // Form validation\n const validate = () => {\n const errs: { title?: string; description?: string } = {};\n if (!reportTitle.trim()) {\n errs.title = 'Title / bug name is required.';\n }\n if (!description.trim()) {\n errs.description = 'Description is required.';\n }\n setErrors(errs);\n return Object.keys(errs).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!validate()) return;\n\n setIsSubmitting(true);\n setSubmitError(null);\n try {\n const reportData: BugReportData = {\n projectUrl,\n title: reportTitle.trim(),\n description: description.trim(),\n screenshots,\n timestamp: new Date().toISOString(),\n meta: {\n url: window.location.href,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n screenSize: {\n width: window.innerWidth,\n height: window.innerHeight,\n },\n },\n };\n\n await onSubmitReport(reportData);\n setIsSuccess(true);\n } catch (err) {\n console.error('Failed to submit bug report:', err);\n setSubmitError(\n err instanceof Error ? err.message : 'Failed to submit bug report. Please try again.'\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleReset = () => {\n setReportTitle('');\n setDescription('');\n setErrors({});\n setSubmitError(null);\n setIsSuccess(false);\n };\n\n // Determine slide animation direction\n const slideClass = isLeft\n ? isOpen\n ? 'translate-x-0 opacity-100 pointer-events-auto'\n : '-translate-x-full opacity-0 pointer-events-none'\n : isOpen\n ? 'translate-x-0 opacity-100 pointer-events-auto'\n : 'translate-x-full opacity-0 pointer-events-none';\n\n return (\n <>\n {/* Subtle backdrop overlay */}\n <div\n data-bugdrop-widget=\"true\"\n onClick={onClose}\n className={`fixed inset-0 z-[99990] bg-slate-900/40 backdrop-blur-sm transition-opacity duration-300 ${\n isOpen ? 'opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'\n }`}\n />\n\n {/* Slide-in Drawer Container */}\n <aside\n data-bugdrop-widget=\"true\"\n className={`fixed top-0 z-[99995] flex h-full w-full max-w-md flex-col bg-white shadow-2xl transition-all duration-300 ease-out sm:max-w-lg ${\n isLeft ? 'left-0 border-r border-slate-200' : 'right-0 border-l border-slate-200'\n } ${slideClass}`}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-5\">\n <div className=\"flex items-center gap-3\">\n <div\n className=\"flex h-10 w-10 items-center justify-center rounded-xl text-white shadow-md font-bold\"\n style={{ backgroundColor: primaryColor }}\n >\n <Sparkles className=\"h-5 w-5\" />\n </div>\n <div>\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-lg font-bold text-slate-800\">{title}</h2>\n <span\n className=\"rounded-md bg-slate-100 px-2 py-0.5 text-[11px] font-semibold tracking-wider text-slate-500\"\n title={projectUrl}\n >\n {projectLabel}\n </span>\n </div>\n <p className=\"mt-0.5 text-xs text-slate-500\">{subtitle}</p>\n </div>\n </div>\n\n <button\n type=\"button\"\n onClick={onClose}\n className=\"flex h-8 w-8 items-center justify-center rounded-lg text-slate-400 transition hover:bg-slate-100 hover:text-slate-600\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n\n {/* Content Area */}\n <div className=\"flex-1 overflow-y-auto px-6 py-5\">\n {isSuccess ? (\n <div className=\"flex h-full flex-col items-center justify-center text-center py-10 animate-fadeIn\">\n <div\n className=\"flex h-16 w-16 items-center justify-center rounded-full text-white shadow-lg mb-4\"\n style={{ backgroundColor: primaryColor }}\n >\n <CheckCircle2 className=\"h-9 w-9\" />\n </div>\n <h3 className=\"text-xl font-bold text-slate-800\">\n Bug Report Submitted!\n </h3>\n <p className=\"mt-2 text-sm text-slate-500 max-w-xs\">\n Thank you! Your bug report with {screenshots.length} screenshot{screenshots.length !== 1 ? 's' : ''} has been captured and logged.\n </p>\n\n <div className=\"mt-8 flex flex-col sm:flex-row gap-3 w-full\">\n <button\n type=\"button\"\n onClick={handleReset}\n className=\"flex-1 rounded-xl border border-slate-200 bg-white py-2.5 text-sm font-semibold text-slate-700 shadow-sm transition hover:bg-slate-50\"\n >\n Report Another Bug\n </button>\n <button\n type=\"button\"\n onClick={onClose}\n style={{ backgroundColor: primaryColor }}\n className=\"flex-1 rounded-xl py-2.5 text-sm font-semibold text-white shadow-md transition hover:brightness-110\"\n >\n Close\n </button>\n </div>\n </div>\n ) : (\n <form onSubmit={handleSubmit} className=\"space-y-5\">\n {/* Bug Title / Name (Required) */}\n <div>\n <label className=\"block text-xs font-bold tracking-wide uppercase text-slate-700\">\n Bug Title / Name <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"text\"\n value={reportTitle}\n onChange={(e) => {\n setReportTitle(e.target.value);\n if (errors.title) setErrors((prev) => ({ ...prev, title: undefined }));\n }}\n placeholder={placeholderTitle}\n className={`mt-1.5 w-full rounded-xl border px-3.5 py-2.5 text-sm transition focus:outline-none focus:ring-2 ${\n errors.title\n ? 'border-red-300 bg-red-50/50 text-red-900 focus:ring-red-400'\n : 'border-slate-200 bg-white text-slate-800 focus:border-transparent focus:ring-blue-500'\n }`}\n />\n {errors.title && (\n <p className=\"mt-1.5 flex items-center gap-1 text-xs text-red-600\">\n <AlertCircle className=\"h-3.5 w-3.5\" />\n <span>{errors.title}</span>\n </p>\n )}\n </div>\n\n {/* Bug Description (Required) */}\n <div>\n <label className=\"block text-xs font-bold tracking-wide uppercase text-slate-700\">\n Description <span className=\"text-red-500\">*</span>\n </label>\n <textarea\n rows={4}\n value={description}\n onChange={(e) => {\n setDescription(e.target.value);\n if (errors.description) {\n setErrors((prev) => ({ ...prev, description: undefined }));\n }\n }}\n placeholder={placeholderDescription}\n className={`mt-1.5 w-full rounded-xl border px-3.5 py-2.5 text-sm transition focus:outline-none focus:ring-2 ${\n errors.description\n ? 'border-red-300 bg-red-50/50 text-red-900 focus:ring-red-400'\n : 'border-slate-200 bg-white text-slate-800 focus:border-transparent focus:ring-blue-500'\n }`}\n />\n {errors.description && (\n <p className=\"mt-1.5 flex items-center gap-1 text-xs text-red-600\">\n <AlertCircle className=\"h-3.5 w-3.5\" />\n <span>{errors.description}</span>\n </p>\n )}\n </div>\n\n {/* Screenshots Section (Max 3, Optional) */}\n <div>\n <div className=\"flex items-center justify-between\">\n <label className=\"block text-xs font-bold tracking-wide uppercase text-slate-700\">\n Screenshots <span className=\"text-slate-400 font-normal lowercase\">(optional)</span>\n </label>\n <span className=\"rounded-full bg-slate-100 px-2 py-0.5 text-xs font-semibold text-slate-600\">\n {screenshots.length} / 3\n </span>\n </div>\n <p className=\"mt-1 text-xs text-slate-500\">\n Capture your screen and annotate with pencil, shapes, or arrows.\n </p>\n\n {/* Screenshot Thumbnails Grid */}\n {screenshots.length > 0 && (\n <div className=\"mt-3 grid grid-cols-3 gap-2.5\">\n {screenshots.map((s, idx) => (\n <div\n key={s.id}\n className=\"group relative aspect-video overflow-hidden rounded-lg border border-slate-200 bg-slate-100 shadow-sm\"\n >\n <img\n src={s.dataUrl}\n alt={`Screenshot ${idx + 1}`}\n className=\"h-full w-full object-cover transition duration-200 group-hover:scale-105\"\n />\n\n {/* Top badge */}\n <span className=\"absolute top-1 left-1 rounded bg-black/60 px-1 py-0.2 text-[10px] font-semibold text-white\">\n #{idx + 1}\n </span>\n\n {/* Hover Overlay with actions */}\n <div className=\"absolute inset-0 flex items-center justify-center gap-1.5 bg-black/50 opacity-0 backdrop-blur-[1px] transition-opacity duration-200 group-hover:opacity-100\">\n <button\n type=\"button\"\n onClick={() => setPreviewImage(s.dataUrl)}\n title=\"Preview screenshot\"\n className=\"flex h-7 w-7 items-center justify-center rounded-md bg-white/90 text-slate-700 shadow transition hover:bg-white hover:text-blue-600\"\n >\n <Eye className=\"h-3.5 w-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => onEditScreenshot(s)}\n title=\"Re-edit / annotate\"\n className=\"flex h-7 w-7 items-center justify-center rounded-md bg-white/90 text-slate-700 shadow transition hover:bg-white hover:text-blue-600\"\n >\n <Edit3 className=\"h-3.5 w-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => onDeleteScreenshot(s.id)}\n title=\"Delete screenshot\"\n className=\"flex h-7 w-7 items-center justify-center rounded-md bg-red-600 text-white shadow transition hover:bg-red-700\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </div>\n ))}\n </div>\n )}\n\n {/* Add Screenshot Trigger Button */}\n <div className=\"mt-3\">\n {screenshots.length < 3 ? (\n <button\n type=\"button\"\n onClick={onTriggerScreenshot}\n className=\"flex w-full items-center justify-center gap-2 rounded-xl border-2 border-dashed border-slate-300 bg-slate-50/70 py-3 text-xs font-semibold text-slate-600 transition hover:border-blue-400 hover:bg-blue-50/50 hover:text-blue-600\"\n >\n <Camera className=\"h-4 w-4 text-slate-500\" />\n <span>\n {screenshots.length === 0\n ? 'Capture Screen & Annotate'\n : `Capture Another Screenshot (${3 - screenshots.length} left)`}\n </span>\n </button>\n ) : (\n <div className=\"rounded-lg bg-amber-50 p-2.5 text-center text-xs text-amber-700 border border-amber-200\">\n Maximum 3 screenshots attached. Delete one to take a new one.\n </div>\n )}\n </div>\n </div>\n\n {submitError && (\n <div className=\"rounded-xl border border-red-200 bg-red-50 px-3.5 py-2.5 text-xs text-red-700 flex items-start gap-2\">\n <AlertCircle className=\"h-4 w-4 shrink-0 mt-0.5\" />\n <span>{submitError}</span>\n </div>\n )}\n\n {/* Form Actions */}\n <div className=\"pt-4 border-t border-slate-100 flex items-center justify-end gap-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-sm font-semibold text-slate-600 transition hover:bg-slate-50\"\n >\n Cancel\n </button>\n\n <button\n type=\"submit\"\n disabled={isSubmitting}\n style={{ backgroundColor: primaryColor }}\n className=\"flex items-center gap-2 rounded-xl px-5 py-2.5 text-sm font-semibold text-white shadow-md transition hover:brightness-110 active:scale-95 disabled:opacity-60\"\n >\n {isSubmitting ? (\n <>\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n <span>Submitting...</span>\n </>\n ) : (\n <span>Submit Bug Report</span>\n )}\n </button>\n </div>\n </form>\n )}\n </div>\n </aside>\n\n {/* Lightbox Preview Modal for zoomed screenshot */}\n {previewImage && (\n <div\n data-bugdrop-widget=\"true\"\n onClick={() => setPreviewImage(null)}\n className=\"fixed inset-0 z-[100001] flex items-center justify-center bg-black/80 p-4 backdrop-blur-sm animate-fadeIn\"\n >\n <div\n className=\"relative max-h-[90vh] max-w-[90vw] overflow-hidden rounded-xl bg-slate-900 shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <img\n src={previewImage}\n alt=\"Screenshot Preview\"\n className=\"max-h-[85vh] w-auto rounded-xl object-contain\"\n />\n <button\n type=\"button\"\n onClick={() => setPreviewImage(null)}\n className=\"absolute top-3 right-3 flex h-8 w-8 items-center justify-center rounded-full bg-black/60 text-white shadow hover:bg-black/90\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n )}\n </>\n );\n};","import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport {\n Stage,\n Layer,\n Image as KonvaImage,\n Line,\n Rect,\n Circle,\n Arrow,\n Transformer,\n} from 'react-konva';\nimport type Konva from 'konva';\nimport {\n Pencil,\n Eraser,\n Square,\n Circle as CircleIcon,\n ArrowUpRight,\n MousePointer,\n Undo2,\n Redo2,\n Trash2,\n Check,\n X,\n Palette,\n} from 'lucide-react';\nimport type {\n EditorTool,\n AnnotationShape,\n LineAnnotation,\n RectAnnotation,\n CircleAnnotation,\n ArrowAnnotation,\n} from '../types';\n\ninterface KonvaEditorProps {\n imageSrc: string;\n onSave: (editedDataUrl: string) => void;\n onCancel: () => void;\n primaryColor?: string;\n}\n\nconst PRESET_COLORS = [\n '#ef4444', // Red\n '#f97316', // Orange\n '#eab308', // Yellow\n '#10b981', // Green\n '#3b82f6', // Blue\n '#8b5cf6', // Purple\n '#ec4899', // Pink\n '#000000', // Black\n '#ffffff', // White\n];\n\nconst STROKE_WIDTHS = [\n { label: 'S', value: 3 },\n { label: 'M', value: 6 },\n { label: 'L', value: 10 },\n { label: 'XL', value: 16 },\n];\n\nexport const KonvaEditor: React.FC<KonvaEditorProps> = ({\n imageSrc,\n onSave,\n onCancel,\n primaryColor = '#2563eb',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const stageRef = useRef<Konva.Stage>(null);\n const transformerRef = useRef<Konva.Transformer>(null);\n\n const [image, setImage] = useState<HTMLImageElement | null>(null);\n const [scale, setScale] = useState<number>(1);\n const [stageDimensions, setStageDimensions] = useState({ width: 800, height: 600 });\n\n // Tool state\n const [tool, setTool] = useState<EditorTool>('pencil');\n const [color, setColor] = useState<string>('#ef4444');\n const [strokeWidth, setStrokeWidth] = useState<number>(6);\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n // Shapes & drawing state\n const [shapes, setShapes] = useState<AnnotationShape[]>([]);\n const [draftShape, setDraftShape] = useState<AnnotationShape | null>(null);\n const [isDrawing, setIsDrawing] = useState(false);\n const [startPoint, setStartPoint] = useState<{ x: number; y: number } | null>(null);\n\n // History stack for Undo / Redo\n const [history, setHistory] = useState<AnnotationShape[][]>([[]]);\n const [historyStep, setHistoryStep] = useState<number>(0);\n\n // Load screenshot image\n useEffect(() => {\n const img = new window.Image();\n img.crossOrigin = 'anonymous';\n img.src = imageSrc;\n img.onload = () => {\n setImage(img);\n };\n }, [imageSrc]);\n\n // Compute responsive stage scaling to fit container\n const updateDimensions = useCallback(() => {\n if (!containerRef.current || !image) return;\n const paddingX = 48;\n const paddingY = 120;\n const availWidth = Math.max(300, containerRef.current.clientWidth - paddingX);\n const availHeight = Math.max(300, containerRef.current.clientHeight - paddingY);\n\n const fitScale = Math.min(\n availWidth / image.naturalWidth,\n availHeight / image.naturalHeight,\n 1\n );\n\n setScale(fitScale);\n setStageDimensions({\n width: Math.round(image.naturalWidth * fitScale),\n height: Math.round(image.naturalHeight * fitScale),\n });\n }, [image]);\n\n useEffect(() => {\n updateDimensions();\n window.addEventListener('resize', updateDimensions);\n return () => window.removeEventListener('resize', updateDimensions);\n }, [updateDimensions]);\n\n // Update Transformer attachment when selection or shapes change\n useEffect(() => {\n if (!transformerRef.current || !stageRef.current) return;\n if (selectedId) {\n const selectedNode = stageRef.current.findOne('#' + selectedId);\n if (selectedNode) {\n transformerRef.current.nodes([selectedNode]);\n transformerRef.current.getLayer()?.batchDraw();\n return;\n }\n }\n transformerRef.current.nodes([]);\n transformerRef.current.getLayer()?.batchDraw();\n }, [selectedId, shapes]);\n\n // Push new state to history\n const pushHistory = useCallback((newShapes: AnnotationShape[]) => {\n setHistory((prev) => {\n const newHistory = prev.slice(0, historyStep + 1);\n newHistory.push(newShapes);\n return newHistory;\n });\n setHistoryStep((prev) => prev + 1);\n }, [historyStep]);\n\n const handleUndo = useCallback(() => {\n if (historyStep > 0) {\n const newStep = historyStep - 1;\n setHistoryStep(newStep);\n setShapes(history[newStep]);\n setSelectedId(null);\n }\n }, [historyStep, history]);\n\n const handleRedo = useCallback(() => {\n if (historyStep < history.length - 1) {\n const newStep = historyStep + 1;\n setHistoryStep(newStep);\n setShapes(history[newStep]);\n setSelectedId(null);\n }\n }, [historyStep, history]);\n\n const handleClearAll = () => {\n if (shapes.length === 0) return;\n const newShapes: AnnotationShape[] = [];\n setShapes(newShapes);\n pushHistory(newShapes);\n setSelectedId(null);\n };\n\n const handleDeleteSelected = useCallback(() => {\n if (!selectedId) return;\n const newShapes = shapes.filter((s) => s.id !== selectedId);\n setShapes(newShapes);\n pushHistory(newShapes);\n setSelectedId(null);\n }, [selectedId, shapes, pushHistory]);\n\n // Keyboard shortcuts\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {\n return;\n }\n if ((e.ctrlKey || e.metaKey) && e.key === 'z') {\n if (e.shiftKey) {\n handleRedo();\n } else {\n handleUndo();\n }\n e.preventDefault();\n } else if ((e.ctrlKey || e.metaKey) && e.key === 'y') {\n handleRedo();\n e.preventDefault();\n } else if (e.key === 'Delete' || e.key === 'Backspace') {\n if (selectedId) {\n handleDeleteSelected();\n e.preventDefault();\n }\n } else if (e.key === 'Escape') {\n setSelectedId(null);\n e.preventDefault();\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [handleDeleteSelected, handleRedo, handleUndo, selectedId]);\n\n // Pointer event handlers for drawing shapes\n const handlePointerDown = (e: Konva.KonvaEventObject<MouseEvent | TouchEvent>) => {\n const stage = stageRef.current;\n if (!stage || !image) return;\n\n const pointer = stage.getPointerPosition();\n if (!pointer) return;\n\n // Convert to unscaled natural image coordinates\n const x = pointer.x / scale;\n const y = pointer.y / scale;\n\n // Select Tool behavior\n if (tool === 'select') {\n const clickedOnEmpty = e.target === stage || e.target.hasName('bg-image');\n if (clickedOnEmpty) {\n setSelectedId(null);\n }\n return;\n }\n\n // Eraser Tool click behavior: if clicked on an existing shape, remove it immediately\n if (tool === 'eraser') {\n const clickedNode = e.target;\n if (clickedNode !== stage && !clickedNode.hasName('bg-image')) {\n const shapeId = clickedNode.id();\n if (shapeId) {\n const newShapes = shapes.filter((s) => s.id !== shapeId);\n setShapes(newShapes);\n pushHistory(newShapes);\n setSelectedId(null);\n return;\n }\n }\n }\n\n // Deselect any selected shape while drawing new annotations\n setSelectedId(null);\n setIsDrawing(true);\n setStartPoint({ x, y });\n\n const id = `shape_${Date.now()}_${Math.random().toString(36).substring(2, 7)}`;\n\n if (tool === 'pencil' || tool === 'eraser') {\n const newLine: LineAnnotation = {\n id,\n type: 'line',\n tool,\n points: [x, y],\n stroke: tool === 'eraser' ? '#ffffff' : color,\n strokeWidth: tool === 'eraser' ? strokeWidth * 2.5 : strokeWidth,\n };\n setDraftShape(newLine);\n } else if (tool === 'rectangle') {\n const newRect: RectAnnotation = {\n id,\n type: 'rectangle',\n x,\n y,\n width: 0,\n height: 0,\n stroke: color,\n strokeWidth,\n };\n setDraftShape(newRect);\n } else if (tool === 'circle') {\n const newCircle: CircleAnnotation = {\n id,\n type: 'circle',\n x,\n y,\n radius: 0,\n stroke: color,\n strokeWidth,\n };\n setDraftShape(newCircle);\n } else if (tool === 'arrow') {\n const newArrow: ArrowAnnotation = {\n id,\n type: 'arrow',\n points: [x, y, x, y],\n stroke: color,\n fill: color,\n strokeWidth,\n };\n setDraftShape(newArrow);\n }\n };\n\n const handlePointerMove = () => {\n if (!isDrawing || !draftShape || !startPoint || !stageRef.current) return;\n\n const pointer = stageRef.current.getPointerPosition();\n if (!pointer) return;\n\n const x = pointer.x / scale;\n const y = pointer.y / scale;\n\n if (draftShape.type === 'line') {\n setDraftShape({\n ...draftShape,\n points: [...draftShape.points, x, y],\n });\n } else if (draftShape.type === 'rectangle') {\n const rx = Math.min(startPoint.x, x);\n const ry = Math.min(startPoint.y, y);\n const rw = Math.abs(x - startPoint.x);\n const rh = Math.abs(y - startPoint.y);\n setDraftShape({\n ...draftShape,\n x: rx,\n y: ry,\n width: rw,\n height: rh,\n });\n } else if (draftShape.type === 'circle') {\n const radius = Math.hypot(x - startPoint.x, y - startPoint.y);\n setDraftShape({\n ...draftShape,\n radius,\n });\n } else if (draftShape.type === 'arrow') {\n setDraftShape({\n ...draftShape,\n points: [startPoint.x, startPoint.y, x, y],\n });\n }\n };\n\n const handlePointerUp = () => {\n if (!isDrawing) return;\n setIsDrawing(false);\n if (!draftShape) return;\n\n let isValid = false;\n if (draftShape.type === 'line' && draftShape.points.length >= 2) {\n isValid = true;\n } else if (\n draftShape.type === 'rectangle' &&\n draftShape.width > 6 &&\n draftShape.height > 6\n ) {\n isValid = true;\n } else if (draftShape.type === 'circle' && draftShape.radius > 5) {\n isValid = true;\n } else if (draftShape.type === 'arrow') {\n const [x1, y1, x2, y2] = draftShape.points;\n if (Math.hypot(x2 - x1, y2 - y1) > 10) {\n isValid = true;\n }\n }\n\n if (isValid) {\n const nextShapes = [...shapes, draftShape];\n setShapes(nextShapes);\n pushHistory(nextShapes);\n\n // Automatically select shapes (rect, circle, arrow) for immediate resizing\n if (\n draftShape.type === 'rectangle' ||\n draftShape.type === 'circle' ||\n draftShape.type === 'arrow'\n ) {\n setSelectedId(draftShape.id);\n setTool('select');\n }\n }\n\n setDraftShape(null);\n setStartPoint(null);\n };\n\n // Transform and Drag updates for resizable shapes\n const handleTransformEnd = (e: Konva.KonvaEventObject<Event>, id: string) => {\n const node = e.target;\n const targetShape = shapes.find((s) => s.id === id);\n if (!targetShape) return;\n\n if (targetShape.type === 'rectangle') {\n const scaleX = node.scaleX();\n const scaleY = node.scaleY();\n node.scaleX(1);\n node.scaleY(1);\n const updated: RectAnnotation = {\n ...targetShape,\n x: node.x(),\n y: node.y(),\n width: Math.max(10, node.width() * scaleX),\n height: Math.max(10, node.height() * scaleY),\n rotation: node.rotation(),\n };\n const nextShapes = shapes.map((s) => (s.id === id ? updated : s));\n setShapes(nextShapes);\n pushHistory(nextShapes);\n } else if (targetShape.type === 'circle') {\n const scaleX = node.scaleX();\n node.scaleX(1);\n node.scaleY(1);\n const updated: CircleAnnotation = {\n ...targetShape,\n x: node.x(),\n y: node.y(),\n radius: Math.max(6, targetShape.radius * scaleX),\n rotation: node.rotation(),\n };\n const nextShapes = shapes.map((s) => (s.id === id ? updated : s));\n setShapes(nextShapes);\n pushHistory(nextShapes);\n } else if (targetShape.type === 'arrow') {\n const scaleX = node.scaleX();\n const scaleY = node.scaleY();\n node.scaleX(1);\n node.scaleY(1);\n const [x1, y1, x2, y2] = targetShape.points;\n const updated: ArrowAnnotation = {\n ...targetShape,\n x: node.x(),\n y: node.y(),\n points: [x1, y1, x1 + (x2 - x1) * scaleX, y1 + (y2 - y1) * scaleY],\n rotation: node.rotation(),\n };\n const nextShapes = shapes.map((s) => (s.id === id ? updated : s));\n setShapes(nextShapes);\n pushHistory(nextShapes);\n }\n };\n\n const handleDragEnd = (e: Konva.KonvaEventObject<DragEvent>, id: string) => {\n const node = e.target;\n const targetShape = shapes.find((s) => s.id === id);\n if (!targetShape) return;\n\n const nextShapes = shapes.map((s) => {\n if (s.id === id) {\n return {\n ...s,\n x: node.x(),\n y: node.y(),\n };\n }\n return s;\n });\n setShapes(nextShapes);\n pushHistory(nextShapes);\n };\n\n // Finalize and export screenshot with annotations\n const handleExport = () => {\n if (!stageRef.current) return;\n // Deselect any transformer handles so they aren't included in the exported image\n setSelectedId(null);\n\n // Allow React state to flush transformer detachment before export\n setTimeout(() => {\n if (!stageRef.current) return;\n const exportedDataUrl = stageRef.current.toDataURL({\n pixelRatio: 1 / scale,\n mimeType: 'image/png',\n });\n onSave(exportedDataUrl);\n }, 60);\n };\n\n return (\n <div\n ref={containerRef}\n className=\"fixed inset-0 z-[100000] flex flex-col bg-slate-950/90 backdrop-blur-md select-none text-white overflow-hidden animate-fadeIn\"\n style={{ touchAction: 'none' }}\n >\n {/* Top Header Bar */}\n <div className=\"flex h-16 shrink-0 items-center justify-between border-b border-slate-800 bg-slate-900/90 px-4 sm:px-6\">\n <div className=\"flex items-center gap-3\">\n <div\n className=\"flex h-8 w-8 items-center justify-center rounded-lg text-white font-bold text-sm shadow\"\n style={{ backgroundColor: primaryColor }}\n >\n BD\n </div>\n <div>\n <h1 className=\"text-sm sm:text-base font-semibold leading-tight text-slate-100\">\n Screenshot Editor\n </h1>\n <p className=\"text-xs text-slate-400 hidden sm:block\">\n Highlight issues with pencil, arrows, circles, and boxes\n </p>\n </div>\n </div>\n\n {/* Top Actions: Undo, Redo, Clear, Cancel, Save */}\n <div className=\"flex items-center gap-2 sm:gap-3\">\n <button\n type=\"button\"\n onClick={handleUndo}\n disabled={historyStep <= 0}\n title=\"Undo (Ctrl+Z)\"\n className=\"flex h-9 w-9 items-center justify-center rounded-lg border border-slate-700 bg-slate-800 text-slate-200 transition hover:bg-slate-700 hover:text-white disabled:opacity-40 disabled:pointer-events-none\"\n >\n <Undo2 className=\"h-4 w-4\" />\n </button>\n <button\n type=\"button\"\n onClick={handleRedo}\n disabled={historyStep >= history.length - 1}\n title=\"Redo (Ctrl+Y)\"\n className=\"flex h-9 w-9 items-center justify-center rounded-lg border border-slate-700 bg-slate-800 text-slate-200 transition hover:bg-slate-700 hover:text-white disabled:opacity-40 disabled:pointer-events-none\"\n >\n <Redo2 className=\"h-4 w-4\" />\n </button>\n <button\n type=\"button\"\n onClick={handleClearAll}\n disabled={shapes.length === 0}\n title=\"Clear all annotations\"\n className=\"flex h-9 items-center gap-1.5 rounded-lg border border-slate-700 bg-slate-800 px-2.5 text-xs font-medium text-slate-300 transition hover:bg-slate-700 hover:text-white disabled:opacity-40 disabled:pointer-events-none\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n <span className=\"hidden md:inline\">Clear All</span>\n </button>\n\n <div className=\"h-5 w-px bg-slate-700 mx-1\" />\n\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"flex h-9 items-center gap-1.5 rounded-lg border border-slate-700 bg-slate-800 px-3 text-xs sm:text-sm font-medium text-slate-200 transition hover:bg-slate-700 hover:text-white\"\n >\n <X className=\"h-4 w-4\" />\n <span>Cancel</span>\n </button>\n\n <button\n type=\"button\"\n onClick={handleExport}\n style={{ backgroundColor: primaryColor }}\n className=\"flex h-9 items-center gap-1.5 rounded-lg px-4 text-xs sm:text-sm font-semibold text-white shadow-md transition hover:brightness-110 active:scale-95\"\n >\n <Check className=\"h-4 w-4\" />\n <span>Add to Report</span>\n </button>\n </div>\n </div>\n\n {/* Floating Toolbar */}\n <div className=\"absolute top-20 left-1/2 -translate-x-1/2 z-20 flex flex-wrap items-center justify-center gap-2 rounded-2xl border border-slate-700/80 bg-slate-900/95 p-2 shadow-2xl backdrop-blur-md\">\n {/* Tool selector buttons */}\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => setTool('select')}\n title=\"Select & Move / Resize\"\n className={`flex h-9 w-9 items-center justify-center rounded-xl transition ${\n tool === 'select'\n ? 'bg-blue-600 text-white shadow-inner'\n : 'text-slate-300 hover:bg-slate-800 hover:text-white'\n }`}\n >\n <MousePointer className=\"h-4 w-4\" />\n </button>\n\n <button\n type=\"button\"\n onClick={() => {\n setTool('pencil');\n setSelectedId(null);\n }}\n title=\"Pencil / Draw\"\n className={`flex h-9 w-9 items-center justify-center rounded-xl transition ${\n tool === 'pencil'\n ? 'bg-blue-600 text-white shadow-inner'\n : 'text-slate-300 hover:bg-slate-800 hover:text-white'\n }`}\n >\n <Pencil className=\"h-4 w-4\" />\n </button>\n\n <button\n type=\"button\"\n onClick={() => {\n setTool('eraser');\n setSelectedId(null);\n }}\n title=\"Eraser (click or drag to erase)\"\n className={`flex h-9 w-9 items-center justify-center rounded-xl transition ${\n tool === 'eraser'\n ? 'bg-blue-600 text-white shadow-inner'\n : 'text-slate-300 hover:bg-slate-800 hover:text-white'\n }`}\n >\n <Eraser className=\"h-4 w-4\" />\n </button>\n\n <button\n type=\"button\"\n onClick={() => {\n setTool('rectangle');\n setSelectedId(null);\n }}\n title=\"Rectangle (Resizable)\"\n className={`flex h-9 w-9 items-center justify-center rounded-xl transition ${\n tool === 'rectangle'\n ? 'bg-blue-600 text-white shadow-inner'\n : 'text-slate-300 hover:bg-slate-800 hover:text-white'\n }`}\n >\n <Square className=\"h-4 w-4\" />\n </button>\n\n <button\n type=\"button\"\n onClick={() => {\n setTool('circle');\n setSelectedId(null);\n }}\n title=\"Circle (Resizable)\"\n className={`flex h-9 w-9 items-center justify-center rounded-xl transition ${\n tool === 'circle'\n ? 'bg-blue-600 text-white shadow-inner'\n : 'text-slate-300 hover:bg-slate-800 hover:text-white'\n }`}\n >\n <CircleIcon className=\"h-4 w-4\" />\n </button>\n\n <button\n type=\"button\"\n onClick={() => {\n setTool('arrow');\n setSelectedId(null);\n }}\n title=\"Arrow (Resizable)\"\n className={`flex h-9 w-9 items-center justify-center rounded-xl transition ${\n tool === 'arrow'\n ? 'bg-blue-600 text-white shadow-inner'\n : 'text-slate-300 hover:bg-slate-800 hover:text-white'\n }`}\n >\n <ArrowUpRight className=\"h-4 w-4\" />\n </button>\n </div>\n\n <div className=\"h-5 w-px bg-slate-700\" />\n\n {/* Color Palette Switcher */}\n <div className=\"flex items-center gap-1.5 px-1\">\n {PRESET_COLORS.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setColor(c)}\n title={c}\n style={{ backgroundColor: c }}\n className={`h-5 w-5 rounded-full border border-slate-700 transition-transform ${\n color === c ? 'scale-125 ring-2 ring-white ring-offset-1 ring-offset-slate-900' : 'hover:scale-110'\n }`}\n />\n ))}\n\n {/* Custom color input */}\n <label\n title=\"Custom Color\"\n className=\"relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-full border border-slate-600 bg-slate-800 text-slate-300 hover:text-white transition\"\n >\n <Palette className=\"h-3.5 w-3.5\" />\n <input\n type=\"color\"\n value={color}\n onChange={(e) => setColor(e.target.value)}\n className=\"absolute inset-0 opacity-0 cursor-pointer\"\n />\n </label>\n </div>\n\n <div className=\"h-5 w-px bg-slate-700\" />\n\n {/* Stroke Width Selector */}\n <div className=\"flex items-center gap-1\">\n {STROKE_WIDTHS.map((sw) => (\n <button\n key={sw.value}\n type=\"button\"\n onClick={() => setStrokeWidth(sw.value)}\n className={`flex h-7 w-7 items-center justify-center rounded-lg text-xs font-semibold transition ${\n strokeWidth === sw.value\n ? 'bg-slate-700 text-white ring-1 ring-slate-400'\n : 'text-slate-400 hover:bg-slate-800 hover:text-white'\n }`}\n >\n {sw.label}\n </button>\n ))}\n </div>\n\n {/* Delete button if a shape is selected */}\n {selectedId && (\n <>\n <div className=\"h-5 w-px bg-slate-700\" />\n <button\n type=\"button\"\n onClick={handleDeleteSelected}\n title=\"Delete Selected Shape (Del / Backspace)\"\n className=\"flex h-8 items-center gap-1.5 rounded-xl bg-red-600/90 px-3 text-xs font-semibold text-white shadow hover:bg-red-600\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n <span>Delete</span>\n </button>\n </>\n )}\n </div>\n\n {/* Main Canvas Workspace */}\n <div className=\"relative flex flex-1 items-center justify-center p-4 overflow-hidden\">\n {!image ? (\n <div className=\"flex flex-col items-center gap-2 text-slate-400\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-blue-500 border-t-transparent\" />\n <p className=\"text-sm\">Loading screenshot...</p>\n </div>\n ) : (\n <div\n className=\"relative shadow-2xl rounded-md overflow-hidden border border-slate-700 bg-slate-900\"\n style={{\n width: stageDimensions.width,\n height: stageDimensions.height,\n cursor:\n tool === 'select'\n ? 'default'\n : tool === 'eraser'\n ? 'cell'\n : 'crosshair',\n }}\n >\n <Stage\n ref={stageRef}\n width={stageDimensions.width}\n height={stageDimensions.height}\n scaleX={scale}\n scaleY={scale}\n onMouseDown={handlePointerDown}\n onMouseMove={handlePointerMove}\n onMouseUp={handlePointerUp}\n onTouchStart={handlePointerDown}\n onTouchMove={handlePointerMove}\n onTouchEnd={handlePointerUp}\n >\n {/* Background Layer: Screenshot Image */}\n <Layer listening={false}>\n <KonvaImage\n name=\"bg-image\"\n image={image}\n width={image.naturalWidth}\n height={image.naturalHeight}\n />\n </Layer>\n\n {/* Annotations Layer */}\n <Layer>\n {shapes.map((shape) => {\n const isSelectable = tool === 'select';\n\n if (shape.type === 'line') {\n return (\n <Line\n key={shape.id}\n id={shape.id}\n points={shape.points}\n stroke={shape.stroke}\n strokeWidth={shape.strokeWidth}\n tension={0.5}\n lineCap=\"round\"\n lineJoin=\"round\"\n globalCompositeOperation={\n shape.tool === 'eraser' ? 'destination-out' : 'source-over'\n }\n draggable={isSelectable && shape.tool !== 'eraser'}\n onClick={() => {\n if (isSelectable) setSelectedId(shape.id);\n if (tool === 'eraser') {\n const next = shapes.filter((s) => s.id !== shape.id);\n setShapes(next);\n pushHistory(next);\n }\n }}\n onTap={() => {\n if (isSelectable) setSelectedId(shape.id);\n }}\n onDragEnd={(e) => handleDragEnd(e, shape.id)}\n />\n );\n }\n\n if (shape.type === 'rectangle') {\n return (\n <Rect\n key={shape.id}\n id={shape.id}\n x={shape.x}\n y={shape.y}\n width={shape.width}\n height={shape.height}\n stroke={shape.stroke}\n strokeWidth={shape.strokeWidth}\n rotation={shape.rotation || 0}\n draggable={isSelectable}\n onClick={() => {\n if (isSelectable) setSelectedId(shape.id);\n if (tool === 'eraser') {\n const next = shapes.filter((s) => s.id !== shape.id);\n setShapes(next);\n pushHistory(next);\n }\n }}\n onTap={() => {\n if (isSelectable) setSelectedId(shape.id);\n }}\n onTransformEnd={(e) => handleTransformEnd(e, shape.id)}\n onDragEnd={(e) => handleDragEnd(e, shape.id)}\n />\n );\n }\n\n if (shape.type === 'circle') {\n return (\n <Circle\n key={shape.id}\n id={shape.id}\n x={shape.x}\n y={shape.y}\n radius={shape.radius}\n stroke={shape.stroke}\n strokeWidth={shape.strokeWidth}\n rotation={shape.rotation || 0}\n draggable={isSelectable}\n onClick={() => {\n if (isSelectable) setSelectedId(shape.id);\n if (tool === 'eraser') {\n const next = shapes.filter((s) => s.id !== shape.id);\n setShapes(next);\n pushHistory(next);\n }\n }}\n onTap={() => {\n if (isSelectable) setSelectedId(shape.id);\n }}\n onTransformEnd={(e) => handleTransformEnd(e, shape.id)}\n onDragEnd={(e) => handleDragEnd(e, shape.id)}\n />\n );\n }\n\n if (shape.type === 'arrow') {\n return (\n <Arrow\n key={shape.id}\n id={shape.id}\n points={shape.points}\n pointerLength={14}\n pointerWidth={14}\n stroke={shape.stroke}\n fill={shape.fill}\n strokeWidth={shape.strokeWidth}\n rotation={shape.rotation || 0}\n draggable={isSelectable}\n onClick={() => {\n if (isSelectable) setSelectedId(shape.id);\n if (tool === 'eraser') {\n const next = shapes.filter((s) => s.id !== shape.id);\n setShapes(next);\n pushHistory(next);\n }\n }}\n onTap={() => {\n if (isSelectable) setSelectedId(shape.id);\n }}\n onTransformEnd={(e) => handleTransformEnd(e, shape.id)}\n onDragEnd={(e) => handleDragEnd(e, shape.id)}\n />\n );\n }\n\n return null;\n })}\n\n {/* Live Draft Shape during drag */}\n {draftShape && (\n <>\n {draftShape.type === 'line' && (\n <Line\n points={draftShape.points}\n stroke={draftShape.stroke}\n strokeWidth={draftShape.strokeWidth}\n tension={0.5}\n lineCap=\"round\"\n lineJoin=\"round\"\n globalCompositeOperation={\n draftShape.tool === 'eraser'\n ? 'destination-out'\n : 'source-over'\n }\n />\n )}\n {draftShape.type === 'rectangle' && (\n <Rect\n x={draftShape.x}\n y={draftShape.y}\n width={draftShape.width}\n height={draftShape.height}\n stroke={draftShape.stroke}\n strokeWidth={draftShape.strokeWidth}\n dash={[6, 4]}\n />\n )}\n {draftShape.type === 'circle' && (\n <Circle\n x={draftShape.x}\n y={draftShape.y}\n radius={draftShape.radius}\n stroke={draftShape.stroke}\n strokeWidth={draftShape.strokeWidth}\n dash={[6, 4]}\n />\n )}\n {draftShape.type === 'arrow' && (\n <Arrow\n points={draftShape.points}\n pointerLength={14}\n pointerWidth={14}\n stroke={draftShape.stroke}\n fill={draftShape.fill}\n strokeWidth={draftShape.strokeWidth}\n dash={[6, 4]}\n />\n )}\n </>\n )}\n\n {/* Transformer for selected shape */}\n <Transformer\n ref={transformerRef}\n rotateEnabled={true}\n enabledAnchors={[\n 'top-left',\n 'top-right',\n 'bottom-left',\n 'bottom-right',\n 'middle-left',\n 'middle-right',\n 'top-center',\n 'bottom-center',\n ]}\n borderStroke=\"#3b82f6\"\n borderDash={[4, 4]}\n anchorFill=\"#ffffff\"\n anchorStroke=\"#3b82f6\"\n anchorSize={9}\n anchorCornerRadius={2}\n boundBoxFunc={(oldBox, newBox) => {\n if (newBox.width < 10 || newBox.height < 10) {\n return oldBox;\n }\n return newBox;\n }}\n />\n </Layer>\n </Stage>\n </div>\n )}\n </div>\n\n {/* Bottom helper hints bar */}\n <div className=\"flex h-10 shrink-0 items-center justify-between border-t border-slate-800 bg-slate-900/80 px-4 text-xs text-slate-400\">\n <div className=\"flex items-center gap-4\">\n <span>\n Active tool: <strong className=\"text-slate-200 capitalize\">{tool}</strong>\n </span>\n <span className=\"hidden sm:inline\">\n Use <kbd className=\"rounded bg-slate-800 px-1 py-0.5 text-slate-300\">Ctrl+Z</kbd> to undo, <kbd className=\"rounded bg-slate-800 px-1 py-0.5 text-slate-300\">Del</kbd> to remove selected shape\n </span>\n </div>\n <div>\n {image && (\n <span>\n Original Resolution: {image.naturalWidth} x {image.naturalHeight}px\n </span>\n )}\n </div>\n </div>\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport html2canvas from 'html2canvas';\nimport { Bug, X } from 'lucide-react';\nimport { Form } from './Form';\nimport { KonvaEditor } from './KonvaEditor';\nimport type {\n WidgetProps,\n WidgetPosition,\n WidgetButtonSize,\n ScreenshotItem,\n BugReportData,\n} from '../types';\n\nexport const Widget: React.FC<WidgetProps> = ({\n projectUrl,\n onSubmit,\n uiSettings = {},\n onSuccess,\n onError,\n isOpen: controlledIsOpen,\n onToggle,\n className = '',\n}) => {\n const {\n position = 'bottom-right',\n primaryColor = '#2563eb',\n buttonSize = 'md',\n buttonText,\n buttonIcon,\n zIndex = 99990,\n } = uiSettings;\n\n // Uncontrolled or controlled open state\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen;\n\n const setOpen = (open: boolean) => {\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(open);\n }\n onToggle?.(open);\n };\n\n // Screenshots state (max 3)\n const [screenshots, setScreenshots] = useState<ScreenshotItem[]>([]);\n\n // Screenshot capture & Konva editor state\n const [isCapturing, setIsCapturing] = useState(false);\n const [isEditorOpen, setIsEditorOpen] = useState(false);\n const [editingScreenshot, setEditingScreenshot] = useState<{\n id?: string;\n dataUrl: string;\n isNew: boolean;\n } | null>(null);\n\n // Position CSS classes for the trigger button\n const getPositionClasses = (pos: WidgetPosition): string => {\n switch (pos) {\n case 'bottom-left':\n return 'bottom-6 left-6';\n case 'top-left':\n return 'top-6 left-6';\n case 'top-right':\n return 'top-6 right-6';\n case 'left':\n return 'top-1/2 -translate-y-1/2 left-4';\n case 'right':\n return 'top-1/2 -translate-y-1/2 right-4';\n case 'bottom-right':\n default:\n return 'bottom-6 right-6';\n }\n };\n\n // Size CSS classes for the trigger button\n const getSizeClasses = (size: WidgetButtonSize): { button: string; icon: string } => {\n switch (size) {\n case 'sm':\n return {\n button: 'h-10 px-3.5 gap-2 text-xs font-semibold rounded-full shadow-md',\n icon: 'h-4 w-4',\n };\n case 'lg':\n return {\n button: 'h-14 px-5 gap-3 text-base font-bold rounded-full shadow-xl',\n icon: 'h-6 w-6',\n };\n case 'md':\n default:\n return {\n button: 'h-12 px-4 gap-2.5 text-sm font-semibold rounded-full shadow-lg',\n icon: 'h-5 w-5',\n };\n }\n };\n\n const sizeClasses = getSizeClasses(buttonSize);\n\n // Take screenshot flow\n const handleTriggerScreenshot = async () => {\n // 1. Mark as capturing to immediately hide all widget UI (button and form)\n setIsCapturing(true);\n\n try {\n // 2. Wait for DOM to repaint without widget elements\n await new Promise((resolve) => setTimeout(resolve, 180));\n\n // 3. Capture screen using html2canvas\n const canvas = await html2canvas(document.documentElement, {\n useCORS: true,\n allowTaint: true,\n logging: false,\n scrollX: 0,\n scrollY: -window.scrollY,\n windowWidth: document.documentElement.offsetWidth,\n windowHeight: document.documentElement.offsetHeight,\n ignoreElements: (element) => {\n return (\n element.getAttribute('data-bugdrop-widget') === 'true' ||\n element.classList.contains('bugdrop-ignore')\n );\n },\n });\n\n const dataUrl = canvas.toDataURL('image/png');\n\n // 4. Open Konva editor with captured screenshot\n setEditingScreenshot({\n dataUrl,\n isNew: true,\n });\n setIsEditorOpen(true);\n } catch (err) {\n console.error('Error taking screenshot:', err);\n alert('Could not capture screenshot. Please try again.');\n } finally {\n setIsCapturing(false);\n }\n };\n\n // Re-edit an existing screenshot from the form\n const handleEditExistingScreenshot = (item: ScreenshotItem) => {\n setEditingScreenshot({\n id: item.id,\n dataUrl: item.dataUrl,\n isNew: false,\n });\n setIsEditorOpen(true);\n };\n\n // Delete a screenshot\n const handleDeleteScreenshot = (id: string) => {\n setScreenshots((prev) => prev.filter((s) => s.id !== id));\n };\n\n // Save edited screenshot from Konva editor\n const handleSaveEditor = (editedDataUrl: string) => {\n if (editingScreenshot?.isNew) {\n if (screenshots.length < 3) {\n const newItem: ScreenshotItem = {\n id: `ss_${Date.now()}_${Math.random().toString(36).substring(2, 6)}`,\n dataUrl: editedDataUrl,\n createdAt: Date.now(),\n };\n setScreenshots((prev) => [...prev, newItem]);\n }\n } else if (editingScreenshot?.id) {\n // Update existing\n setScreenshots((prev) =>\n prev.map((s) =>\n s.id === editingScreenshot.id ? { ...s, dataUrl: editedDataUrl } : s\n )\n );\n }\n\n setIsEditorOpen(false);\n setEditingScreenshot(null);\n setOpen(true); // Return to form\n };\n\n // Cancel Konva editor\n const handleCancelEditor = () => {\n setIsEditorOpen(false);\n setEditingScreenshot(null);\n setOpen(true); // Return to form\n };\n\n // Hand off the report to the consumer's onSubmit handler\n const handleSubmitReport = async (reportData: BugReportData) => {\n try {\n await onSubmit(reportData);\n onSuccess?.(reportData);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to submit bug report');\n onError?.(error);\n throw error;\n }\n };\n\n // If capturing screenshot, completely hide widget elements from DOM/render\n if (isCapturing) {\n return null;\n }\n\n return (\n <>\n {/* Floating Widget Trigger Button */}\n {!isEditorOpen && (\n <div\n data-bugdrop-widget=\"true\"\n className={`fixed ${getPositionClasses(position)} ${className}`}\n style={{ zIndex }}\n >\n <button\n type=\"button\"\n onClick={() => setOpen(!isOpen)}\n style={{ backgroundColor: primaryColor }}\n className={`group flex items-center justify-center text-white transition-all duration-200 hover:brightness-110 active:scale-95 ${sizeClasses.button}`}\n aria-label={isOpen ? 'Close bug report form' : 'Open bug report form'}\n title={isOpen ? 'Close Bug Report' : 'Report a Bug'}\n >\n {isOpen ? (\n <X className={sizeClasses.icon} />\n ) : buttonIcon ? (\n buttonIcon\n ) : (\n <Bug className={sizeClasses.icon} />\n )}\n\n {buttonText && <span>{buttonText}</span>}\n\n {/* Notification Badge if screenshots are attached */}\n {screenshots.length > 0 && !isOpen && (\n <span className=\"flex h-5 w-5 items-center justify-center rounded-full bg-white text-[11px] font-bold text-slate-900 shadow\">\n {screenshots.length}\n </span>\n )}\n </button>\n </div>\n )}\n\n {/* Slide-in Form Drawer */}\n {!isEditorOpen && (\n <Form\n projectUrl={projectUrl}\n isOpen={isOpen}\n onClose={() => setOpen(false)}\n uiSettings={uiSettings}\n screenshots={screenshots}\n onTriggerScreenshot={handleTriggerScreenshot}\n onEditScreenshot={handleEditExistingScreenshot}\n onDeleteScreenshot={handleDeleteScreenshot}\n onSubmitReport={handleSubmitReport}\n />\n )}\n\n {/* Konva Annotation Editor Modal */}\n {isEditorOpen && editingScreenshot && (\n <KonvaEditor\n imageSrc={editingScreenshot.dataUrl}\n onSave={handleSaveEditor}\n onCancel={handleCancelEditor}\n primaryColor={primaryColor}\n />\n )}\n </>\n );\n};"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { default as React } from 'react';
2
+ import { BugReportData, ScreenshotItem, WidgetUiSettings } from '../types';
3
+ interface FormProps {
4
+ projectUrl: string;
5
+ isOpen: boolean;
6
+ onClose: () => void;
7
+ uiSettings?: WidgetUiSettings;
8
+ screenshots: ScreenshotItem[];
9
+ onTriggerScreenshot: () => void;
10
+ onEditScreenshot: (screenshot: ScreenshotItem) => void;
11
+ onDeleteScreenshot: (id: string) => void;
12
+ onSubmitReport: (data: BugReportData) => Promise<void> | void;
13
+ }
14
+ export declare const Form: React.FC<FormProps>;
15
+ export {};
16
+ //# sourceMappingURL=Form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Form.d.ts","sourceRoot":"","sources":["../../src/components/Form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAYxC,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,gBAAgB,EAEjB,MAAM,UAAU,CAAC;AAElB,UAAU,SAAS;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,gBAAgB,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,IAAI,CAAC;IACvD,kBAAkB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,cAAc,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC/D;AAUD,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CAiZpC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { default as React } from 'react';
2
+ interface KonvaEditorProps {
3
+ imageSrc: string;
4
+ onSave: (editedDataUrl: string) => void;
5
+ onCancel: () => void;
6
+ primaryColor?: string;
7
+ }
8
+ export declare const KonvaEditor: React.FC<KonvaEditorProps>;
9
+ export {};
10
+ //# sourceMappingURL=KonvaEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KonvaEditor.d.ts","sourceRoot":"","sources":["../../src/components/KonvaEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAmCxE,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqBD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA+6BlD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ import { WidgetProps } from '../types';
3
+ export declare const Widget: React.FC<WidgetProps>;
4
+ //# sourceMappingURL=Widget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Widget.d.ts","sourceRoot":"","sources":["../../src/components/Widget.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAKxC,OAAO,KAAK,EACV,WAAW,EAKZ,MAAM,UAAU,CAAC;AAElB,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA8PxC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { Widget } from './components/Widget';
2
+ export type { WidgetProps, WidgetUiSettings, WidgetPosition, WidgetButtonSize, BugReportData, BugReportMetadata, ScreenshotItem, } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,cAAc,CAAC;AAEtB,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,SAAS,CAAC"}
@@ -0,0 +1,112 @@
1
+ import { ReactNode } from 'react';
2
+ export type WidgetPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'left' | 'right';
3
+ export type WidgetButtonSize = 'sm' | 'md' | 'lg';
4
+ export interface WidgetUiSettings {
5
+ /**
6
+ * Position of the widget button and drawer slide direction.
7
+ * Right-aligned positions slide the form in/out from the right.
8
+ * Left-aligned positions slide the form in/out from the left.
9
+ * Default: 'bottom-right'
10
+ */
11
+ position?: WidgetPosition;
12
+ /** Primary theme color for button, highlights, and primary actions. Default: '#2563eb' */
13
+ primaryColor?: string;
14
+ /** Secondary or accent color */
15
+ secondaryColor?: string;
16
+ /** Button size preset. Default: 'md' */
17
+ buttonSize?: WidgetButtonSize;
18
+ /** Optional text label next to the button icon */
19
+ buttonText?: string;
20
+ /** Custom button icon (defaults to Bug icon) */
21
+ buttonIcon?: ReactNode;
22
+ /** Widget header title in the form. Default: 'Report a Bug' */
23
+ title?: string;
24
+ /** Widget header subtitle in the form */
25
+ subtitle?: string;
26
+ /** Custom placeholder for the bug title input */
27
+ placeholderTitle?: string;
28
+ /** Custom placeholder for the bug description input */
29
+ placeholderDescription?: string;
30
+ /** Z-index for the widget overlays. Default: 99999 */
31
+ zIndex?: number;
32
+ }
33
+ export interface ScreenshotItem {
34
+ id: string;
35
+ dataUrl: string;
36
+ createdAt: number;
37
+ }
38
+ export interface BugReportMetadata {
39
+ url: string;
40
+ userAgent: string;
41
+ timestamp?: string;
42
+ screenSize: {
43
+ width: number;
44
+ height: number;
45
+ };
46
+ }
47
+ export interface BugReportData {
48
+ projectUrl: string;
49
+ title: string;
50
+ description: string;
51
+ screenshots: ScreenshotItem[];
52
+ timestamp: string;
53
+ meta: BugReportMetadata;
54
+ }
55
+ export interface WidgetProps {
56
+ /** Project URL included in the report payload (e.g. your backend project endpoint) */
57
+ projectUrl: string;
58
+ /**
59
+ * Required. Called when the user submits a bug report.
60
+ * Send the data to your API (or anywhere) from this handler.
61
+ * Throw or return a rejected promise to show an error in the form.
62
+ */
63
+ onSubmit: (data: BugReportData) => Promise<void> | void;
64
+ /** UI appearance and positioning settings shared by button and form */
65
+ uiSettings?: WidgetUiSettings;
66
+ /** Fired after onSubmit resolves successfully */
67
+ onSuccess?: (data: BugReportData) => void;
68
+ /** Fired when onSubmit throws or rejects */
69
+ onError?: (error: Error) => void;
70
+ /** Controlled open state for the form (optional) */
71
+ isOpen?: boolean;
72
+ /** Callback fired when form open state changes */
73
+ onToggle?: (open: boolean) => void;
74
+ /** Additional custom class names */
75
+ className?: string;
76
+ }
77
+ export type EditorTool = 'select' | 'pencil' | 'eraser' | 'rectangle' | 'circle' | 'arrow';
78
+ export interface BaseAnnotation {
79
+ id: string;
80
+ stroke: string;
81
+ strokeWidth: number;
82
+ }
83
+ export interface LineAnnotation extends BaseAnnotation {
84
+ type: 'line';
85
+ points: number[];
86
+ tool: 'pencil' | 'eraser';
87
+ }
88
+ export interface RectAnnotation extends BaseAnnotation {
89
+ type: 'rectangle';
90
+ x: number;
91
+ y: number;
92
+ width: number;
93
+ height: number;
94
+ rotation?: number;
95
+ }
96
+ export interface CircleAnnotation extends BaseAnnotation {
97
+ type: 'circle';
98
+ x: number;
99
+ y: number;
100
+ radius: number;
101
+ rotation?: number;
102
+ }
103
+ export interface ArrowAnnotation extends BaseAnnotation {
104
+ type: 'arrow';
105
+ points: number[];
106
+ fill: string;
107
+ x?: number;
108
+ y?: number;
109
+ rotation?: number;
110
+ }
111
+ export type AnnotationShape = LineAnnotation | RectAnnotation | CircleAnnotation | ArrowAnnotation;
112
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,72 @@
1
1
  {
2
2
  "name": "bug-widget-library",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Embeddable React bug reporting widget with screenshot capture and Konva annotation",
5
+ "type": "module",
6
+ "main": "./dist/bug-widget-library.cjs",
7
+ "module": "./dist/bug-widget-library.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/bug-widget-library.js",
13
+ "require": "./dist/bug-widget-library.cjs"
14
+ },
15
+ "./style.css": "./dist/bug-widget-library.css"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "sideEffects": [
22
+ "**/*.css"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsc -b && vite build",
26
+ "typecheck": "tsc -b --pretty false",
27
+ "lint": "eslint .",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "peerDependencies": {
31
+ "react": ">=18.0.0",
32
+ "react-dom": ">=18.0.0"
33
+ },
34
+ "dependencies": {
35
+ "html2canvas": "^1.4.1",
36
+ "konva": "^10.7.1",
37
+ "lucide-react": "^1.55.0",
38
+ "react-konva": "^19.3.0"
39
+ },
40
+ "devDependencies": {
41
+ "@eslint/js": "^10.0.1",
42
+ "@types/node": "^24.13.3",
43
+ "@types/react": "^19.2.18",
44
+ "@types/react-dom": "^19.2.7",
45
+ "@vitejs/plugin-react": "^6.1.1",
46
+ "autoprefixer": "^10.6.1",
47
+ "eslint": "^10.10.0",
48
+ "eslint-plugin-react-hooks": "^7.1.1",
49
+ "globals": "^17.12.0",
50
+ "postcss": "^8.5.29",
51
+ "react": "^19.2.8",
52
+ "react-dom": "^19.2.8",
53
+ "tailwindcss": "^3.4.19",
54
+ "typescript": "~6.0.2",
55
+ "typescript-eslint": "^8.69.0",
56
+ "vite": "^8.3.0",
57
+ "vite-plugin-dts": "^5.1.2"
58
+ },
59
+ "keywords": [
60
+ "react",
61
+ "bug-report",
62
+ "widget",
63
+ "screenshot",
64
+ "annotation",
65
+ "konva",
66
+ "feedback"
67
+ ],
68
+ "license": "MIT",
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }