react-signature-canvas-component
Version:
A responsive signature canvas component for React and Next.js applications.
1 lines • 19.2 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.jsx"],"sourcesContent":["// src/index.jsx\r\n\"use client\"; // IMPORTANT: Keep this at the very top of this file\r\n\r\nimport React, { useState, useRef, useEffect, useImperativeHandle } from \"react\";\r\nimport {\r\n RotateCcw,\r\n Palette,\r\n Minus, // Not used in your component\r\n Plus, // Not used in your component\r\n Pen,\r\n PaletteIcon, // Not used in your component, `Palette` is used\r\n} from \"lucide-react\";\r\n\r\nconst SignatureCanvas = React.forwardRef(\r\n ({ onSignatureChange, disabled = false, controls = true, title = 'Draw Your Signature', info = true }, ref) => {\r\n const canvasRef = useRef(null);\r\n const [isDrawing, setIsDrawing] = useState(false);\r\n const [lastPoint, setLastPoint] = useState(null);\r\n const [isEmpty, setIsEmpty] = useState(true);\r\n const [strokeColor, setStrokeColor] = useState(\"#1f2937\");\r\n const [strokeWidth, setStrokeWidth] = useState(3);\r\n const [showColorPicker, setShowColorPicker] = useState(false); // This state isn't currently used to toggle a UI. It should be used for a popover color picker.\r\n\r\n // You currently have a native color input which handles its own UI.\r\n // If you intended a custom popover, you'd use showColorPicker to conditionally render it.\r\n // For now, let's assume the native input is fine and this state can be removed if not needed.\r\n // For demonstration, let's keep it but note its current non-use in the UI.\r\n\r\n const colors = [\r\n \"#1f2937\", // Dark gray (default)\r\n \"#9ca3af\", // light gray (default)\r\n \"#000000\", // Black\r\n \"#3b82f6\", // Blue\r\n \"#059669\", // Green\r\n \"#dc2626\", // Red\r\n \"#7c2d12\", // Brown\r\n ];\r\n\r\n // Helper to get coordinates relative to the canvas\r\n const getCoordinates = (e) => {\r\n const canvas = canvasRef.current;\r\n const rect = canvas.getBoundingClientRect();\r\n const scaleX = canvas.width / rect.width;\r\n const scaleY = canvas.height / rect.height;\r\n\r\n return {\r\n x: (e.clientX - rect.left) * scaleX,\r\n y: (e.clientY - rect.top) * scaleY,\r\n };\r\n };\r\n\r\n // Helper for touch events\r\n const getTouchCoordinates = (touch) => {\r\n const canvas = canvasRef.current;\r\n const rect = canvas.getBoundingClientRect();\r\n const scaleX = canvas.width / rect.width;\r\n const scaleY = canvas.height / rect.height;\r\n\r\n return {\r\n x: (touch.clientX - rect.left) * scaleX,\r\n y: (touch.clientY - rect.top) * scaleY,\r\n };\r\n };\r\n\r\n const startDrawing = (e) => {\r\n if (disabled) return;\r\n e.preventDefault();\r\n setIsDrawing(true);\r\n const point = getCoordinates(e);\r\n setLastPoint(point);\r\n\r\n // Draw a single dot for click without drag\r\n const canvas = canvasRef.current;\r\n const ctx = canvas.getContext(\"2d\");\r\n ctx.beginPath();\r\n ctx.arc(point.x, point.y, strokeWidth / 2, 0, 2 * Math.PI);\r\n ctx.fillStyle = strokeColor;\r\n ctx.fill();\r\n };\r\n\r\n const startTouchDrawing = (e) => {\r\n if (disabled) return;\r\n e.preventDefault();\r\n setIsDrawing(true);\r\n const touch = e.touches[0];\r\n const point = getTouchCoordinates(touch);\r\n setLastPoint(point);\r\n\r\n // Draw a single dot for touch without drag\r\n const canvas = canvasRef.current;\r\n const ctx = canvas.getContext(\"2d\");\r\n ctx.beginPath();\r\n ctx.arc(point.x, point.y, strokeWidth / 2, 0, 2 * Math.PI);\r\n ctx.fillStyle = strokeColor;\r\n ctx.fill();\r\n };\r\n\r\n const draw = (e) => {\r\n if (!isDrawing || disabled) return;\r\n e.preventDefault();\r\n\r\n const canvas = canvasRef.current;\r\n const ctx = canvas.getContext(\"2d\");\r\n const currentPoint = getCoordinates(e);\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(lastPoint.x, lastPoint.y);\r\n ctx.lineTo(currentPoint.x, currentPoint.y);\r\n ctx.strokeStyle = strokeColor;\r\n ctx.lineWidth = strokeWidth;\r\n ctx.lineCap = \"round\";\r\n ctx.lineJoin = \"round\";\r\n ctx.stroke();\r\n\r\n setLastPoint(currentPoint);\r\n };\r\n\r\n const drawTouch = (e) => {\r\n if (!isDrawing || disabled) return;\r\n e.preventDefault();\r\n\r\n const canvas = canvasRef.current;\r\n const ctx = canvas.getContext(\"2d\");\r\n const touch = e.touches[0];\r\n const currentPoint = getTouchCoordinates(touch);\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(lastPoint.x, lastPoint.y);\r\n ctx.lineTo(currentPoint.x, currentPoint.y);\r\n ctx.strokeStyle = strokeColor;\r\n ctx.lineWidth = strokeWidth;\r\n ctx.lineCap = \"round\";\r\n ctx.lineJoin = \"round\";\r\n ctx.stroke();\r\n\r\n setLastPoint(currentPoint);\r\n };\r\n\r\n const stopDrawing = () => {\r\n setIsDrawing(false);\r\n setLastPoint(null);\r\n updateSignatureState(); // Update state when drawing stops\r\n };\r\n\r\n const checkIfEmpty = () => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return true; // Canvas might not be rendered yet\r\n const ctx = canvas.getContext(\"2d\");\r\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n const data = imageData.data;\r\n\r\n for (let i = 0; i < data.length; i += 4) {\r\n if (data[i + 3] > 0) {\r\n return false; // Found a non-transparent pixel\r\n }\r\n }\r\n return true; // All pixels are transparent\r\n };\r\n\r\n const updateSignatureState = () => {\r\n const empty = checkIfEmpty();\r\n setIsEmpty(empty);\r\n if (onSignatureChange) {\r\n onSignatureChange(empty);\r\n }\r\n };\r\n\r\n const clearCanvas = () => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext(\"2d\");\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n setIsEmpty(true);\r\n if (onSignatureChange) {\r\n onSignatureChange(true);\r\n }\r\n };\r\n\r\n const getSignatureData = () => {\r\n if (checkIfEmpty()) return null; // Return null if canvas is empty\r\n return canvasRef.current.toDataURL(\"image/png\");\r\n };\r\n\r\n const getSignatureBlob = () => {\r\n return new Promise((resolve) => {\r\n if (checkIfEmpty()) {\r\n resolve(null); // Resolve with null if canvas is empty\r\n return;\r\n }\r\n canvasRef.current.toBlob(resolve, \"image/png\");\r\n });\r\n };\r\n\r\n // Expose methods to parent component via ref\r\n React.useImperativeHandle(ref, () => ({\r\n getSignatureData,\r\n getSignatureBlob,\r\n checkIfEmpty,\r\n clearCanvas,\r\n // isEmpty is a state, not a method, can be accessed via ref.current.isEmpty (if needed, though checkIfEmpty covers it)\r\n }));\r\n\r\n const adjustStrokeWidth = (delta) => {\r\n const newWidth = Math.max(1, Math.min(10, strokeWidth + delta));\r\n setStrokeWidth(newWidth);\r\n };\r\n\r\n // Effect to clear canvas when disabled state changes\r\n useEffect(() => {\r\n if (disabled) {\r\n clearCanvas(); // Clear if disabled\r\n }\r\n }, [disabled]);\r\n\r\n // Initialize canvas on mount (and re-initialize on resize if needed, though not implemented here)\r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (canvas) {\r\n // Set initial dimensions if not already set or fixed\r\n // It's good practice to ensure canvas internal dimensions match display dimensions for sharp drawing.\r\n // Your current setup with fixed width/height props and `w-full h-auto` style handles responsiveness.\r\n // However, if the canvas parent resizes, the canvas internal dimensions *don't* automatically change.\r\n // For a robust solution, you might want a ResizeObserver here.\r\n }\r\n }, []);\r\n\r\n\r\n return (\r\n <div className=\"space-y-4\">\r\n <div className=\"flex items-center justify-between\">\r\n <label className=\"block text-sm font-medium text-gray-700\">\r\n {title}\r\n </label>\r\n\r\n {/* Drawing Controls */}\r\n <div className=\"flex items-center space-x-2\">\r\n {/* Stroke Width Controls */}\r\n {controls && <div className=\"flex items-center space-x-1 bg-gray-100 rounded-lg p-1\">\r\n <button\r\n onClick={() => setStrokeWidth(3)}\r\n disabled={disabled}\r\n className=\"p-1 text-gray-600 hover:text-gray-800 disabled:opacity-50 disabled:cursor-not-allowed\"\r\n title=\"Set stroke width to 3px\"\r\n >\r\n <Pen className=\"w-3 h-3\" /> {/* Removed fill=\"black\" to use currentColor */}\r\n </button>\r\n <button\r\n onClick={() => setStrokeWidth(4)}\r\n disabled={disabled}\r\n className=\"p-1 text-gray-600 hover:text-gray-800 disabled:opacity-50 disabled:cursor-not-allowed\"\r\n title=\"Set stroke width to 4px\"\r\n >\r\n <Pen className=\"w-4 h-4\" /> {/* Removed fill=\"black\" to use currentColor */}\r\n </button>\r\n <button\r\n onClick={() => setStrokeWidth(5)}\r\n disabled={disabled}\r\n className=\"p-1 text-gray-600 hover:text-gray-800 disabled:opacity-50 disabled:cursor-not-allowed\"\r\n title=\"Set stroke width to 5px\"\r\n >\r\n <Pen className=\"w-5 h-5\" /> {/* Removed fill=\"black\" to use currentColor */}\r\n </button>\r\n </div>}\r\n\r\n {/* Color Picker */}\r\n\r\n <div className=\"relative\">\r\n <label\r\n htmlFor=\"signature-color-picker\"\r\n className={`flex items-center space-x-2 px-3 py-1 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors disabled:opacity-50 ${disabled ? \"cursor-not-allowed\" : \"cursor-pointer\"\r\n }`}\r\n title=\"Choose color\"\r\n >\r\n <Palette className=\"w-4 h-4 text-gray-600\" />\r\n <div\r\n className=\"w-4 h-4 rounded border-2 border-white shadow-sm\"\r\n style={{ backgroundColor: strokeColor }}\r\n />\r\n <input\r\n type=\"color\"\r\n id=\"signature-color-picker\"\r\n value={strokeColor}\r\n onChange={(e) => setStrokeColor(e.target.value)}\r\n disabled={disabled}\r\n className=\"absolute inset-0 w-full h-full opacity-0 cursor-pointer\"\r\n />\r\n </label>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div\r\n className={`border-2 border-dashed rounded-lg p-4 transition-colors ${disabled\r\n ? \"border-gray-200 bg-gray-50\"\r\n : \"border-gray-300 bg-gray-50\"\r\n }`}\r\n >\r\n <canvas\r\n ref={canvasRef}\r\n width={500}\r\n height={200}\r\n className={`w-full border border-gray-200 rounded bg-white touch-none ${disabled ? \"cursor-not-allowed opacity-50\" : \"cursor-crosshair\"\r\n }`}\r\n style={{ maxWidth: \"100%\", height: \"auto\" }}\r\n onMouseDown={startDrawing}\r\n onMouseMove={draw}\r\n onMouseUp={stopDrawing}\r\n onMouseLeave={stopDrawing}\r\n onTouchStart={startTouchDrawing}\r\n onTouchMove={drawTouch}\r\n onTouchEnd={stopDrawing}\r\n />\r\n\r\n {info && <div className=\"flex justify-between items-center mt-3\">\r\n <button\r\n onClick={clearCanvas}\r\n disabled={disabled}\r\n className=\"flex items-center space-x-2 px-3 py-2 text-sm text-gray-600 hover:text-gray-800 hover:bg-gray-100 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\r\n >\r\n <RotateCcw className=\"w-4 h-4\" />\r\n <span>Clear Signature</span>\r\n </button>\r\n\r\n <div\r\n className={`text-xs px-3 py-1 rounded-full ${isEmpty\r\n ? \"text-amber-700 bg-amber-100\"\r\n : \"text-green-700 bg-green-100\"\r\n }`}\r\n >\r\n {isEmpty ? \"Please sign above\" : \"Signature ready\"}\r\n </div>\r\n </div>}\r\n </div>\r\n\r\n {/* This div was for a custom color picker popover, but currently isn't used as the input type=\"color\" handles it.\r\n If you implement a custom popover, you'd render it here based on `showColorPicker` and use this div to close it on outside click.\r\n */}\r\n {showColorPicker && (\r\n <div\r\n className=\"fixed inset-0 z-5\"\r\n onClick={() => setShowColorPicker(false)}\r\n />\r\n )}\r\n </div>\r\n );\r\n }\r\n);\r\n\r\nSignatureCanvas.displayName = \"SignatureCanvas\";\r\n\r\nexport default SignatureCanvas;"],"mappings":"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","names":["React","useState","useRef","useEffect","RotateCcw","Palette","Pen","jsx","jsxs","SignatureCanvas","onSignatureChange","disabled","controls","title","info","ref","canvasRef","isDrawing","setIsDrawing","lastPoint","setLastPoint","isEmpty","setIsEmpty","strokeColor","setStrokeColor","strokeWidth","setStrokeWidth","showColorPicker","setShowColorPicker","colors","getCoordinates","e","canvas","rect","scaleX","scaleY","getTouchCoordinates","touch","startDrawing","point","ctx","startTouchDrawing","draw","currentPoint","drawTouch","stopDrawing","updateSignatureState","checkIfEmpty","data","i","empty","clearCanvas","getSignatureData","getSignatureBlob","resolve","adjustStrokeWidth","delta","newWidth","index_default"]}