mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-24 04:26:14 +00:00
text and improved drawing
This commit is contained in:
parent
10672403c9
commit
efc0c1aab3
@ -1,6 +1,6 @@
|
|||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Stack, TextInput, FileInput, Paper, Group, Button, Text, Alert, Modal, ColorSwatch, Menu, ActionIcon, Slider } from '@mantine/core';
|
import { Stack, TextInput, FileInput, Paper, Group, Button, Text, Alert, Modal, ColorSwatch, Menu, ActionIcon, Slider, Select, Combobox, useCombobox } from '@mantine/core';
|
||||||
import ButtonSelector from "../../shared/ButtonSelector";
|
import ButtonSelector from "../../shared/ButtonSelector";
|
||||||
import { SignParameters } from "../../../hooks/tools/sign/useSignParameters";
|
import { SignParameters } from "../../../hooks/tools/sign/useSignParameters";
|
||||||
|
|
||||||
@ -23,9 +23,14 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
const [imageSignatureData, setImageSignatureData] = useState<string | null>(null);
|
const [imageSignatureData, setImageSignatureData] = useState<string | null>(null);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const modalCanvasRef = useRef<HTMLCanvasElement>(null);
|
const modalCanvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
|
const visibleModalCanvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
const [isModalDrawing, setIsModalDrawing] = useState(false);
|
const [isModalDrawing, setIsModalDrawing] = useState(false);
|
||||||
const [selectedColor, setSelectedColor] = useState('#000000');
|
const [selectedColor, setSelectedColor] = useState('#000000');
|
||||||
const [penSize, setPenSize] = useState(2);
|
const [penSize, setPenSize] = useState(2);
|
||||||
|
const [penSizeInput, setPenSizeInput] = useState('2');
|
||||||
|
const [fontSizeInput, setFontSizeInput] = useState((parameters.fontSize || 16).toString());
|
||||||
|
const fontSizeCombobox = useCombobox();
|
||||||
|
const penSizeCombobox = useCombobox();
|
||||||
|
|
||||||
// Drawing functions for signature canvas
|
// Drawing functions for signature canvas
|
||||||
const startDrawing = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
const startDrawing = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
@ -41,6 +46,9 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
const ctx = canvasRef.current.getContext('2d');
|
const ctx = canvasRef.current.getContext('2d');
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.strokeStyle = selectedColor;
|
ctx.strokeStyle = selectedColor;
|
||||||
|
ctx.lineWidth = penSize;
|
||||||
|
ctx.lineCap = 'round';
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(x, y);
|
ctx.moveTo(x, y);
|
||||||
}
|
}
|
||||||
@ -59,6 +67,11 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.lineTo(x, y);
|
ctx.lineTo(x, y);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Update signature data immediately after each stroke
|
||||||
|
const dataURL = canvasRef.current.toDataURL('image/png');
|
||||||
|
setCanvasSignatureData(dataURL);
|
||||||
|
onParameterChange('signatureData', dataURL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,7 +83,6 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
// Save canvas as signature data
|
// Save canvas as signature data
|
||||||
if (canvasRef.current) {
|
if (canvasRef.current) {
|
||||||
const dataURL = canvasRef.current.toDataURL('image/png');
|
const dataURL = canvasRef.current.toDataURL('image/png');
|
||||||
console.log('Saving canvas signature data:', dataURL.substring(0, 50) + '...');
|
|
||||||
setCanvasSignatureData(dataURL);
|
setCanvasSignatureData(dataURL);
|
||||||
onParameterChange('signatureData', dataURL);
|
onParameterChange('signatureData', dataURL);
|
||||||
|
|
||||||
@ -89,44 +101,89 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
const ctx = canvasRef.current.getContext('2d');
|
const ctx = canvasRef.current.getContext('2d');
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
||||||
|
|
||||||
|
// Also clear the modal canvas if it exists
|
||||||
|
if (modalCanvasRef.current) {
|
||||||
|
const modalCtx = modalCanvasRef.current.getContext('2d');
|
||||||
|
if (modalCtx) {
|
||||||
|
modalCtx.clearRect(0, 0, modalCanvasRef.current.width, modalCanvasRef.current.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setCanvasSignatureData(null);
|
setCanvasSignatureData(null);
|
||||||
onParameterChange('signatureData', undefined);
|
onParameterChange('signatureData', undefined);
|
||||||
|
|
||||||
|
// Deactivate signature placement when cleared
|
||||||
|
if (onDeactivateSignature) {
|
||||||
|
onDeactivateSignature();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Modal canvas drawing functions
|
// Modal canvas drawing functions
|
||||||
const startModalDrawing = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
const startModalDrawing = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
if (!modalCanvasRef.current) return;
|
if (!visibleModalCanvasRef.current || !modalCanvasRef.current) return;
|
||||||
|
|
||||||
setIsModalDrawing(true);
|
setIsModalDrawing(true);
|
||||||
const rect = modalCanvasRef.current.getBoundingClientRect();
|
const rect = visibleModalCanvasRef.current.getBoundingClientRect();
|
||||||
const scaleX = modalCanvasRef.current.width / rect.width;
|
const scaleX = visibleModalCanvasRef.current.width / rect.width;
|
||||||
const scaleY = modalCanvasRef.current.height / rect.height;
|
const scaleY = visibleModalCanvasRef.current.height / rect.height;
|
||||||
const x = (e.clientX - rect.left) * scaleX;
|
const x = (e.clientX - rect.left) * scaleX;
|
||||||
const y = (e.clientY - rect.top) * scaleY;
|
const y = (e.clientY - rect.top) * scaleY;
|
||||||
|
|
||||||
const ctx = modalCanvasRef.current.getContext('2d');
|
// Draw on both the visible modal canvas and hidden canvas
|
||||||
|
const visibleCtx = visibleModalCanvasRef.current.getContext('2d');
|
||||||
|
const hiddenCtx = modalCanvasRef.current.getContext('2d');
|
||||||
|
|
||||||
|
[visibleCtx, hiddenCtx].forEach(ctx => {
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.strokeStyle = selectedColor;
|
ctx.strokeStyle = selectedColor;
|
||||||
|
ctx.lineWidth = penSize;
|
||||||
|
ctx.lineCap = 'round';
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(x, y);
|
ctx.moveTo(x, y);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const drawModal = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
const drawModal = (e: React.MouseEvent<HTMLCanvasElement>) => {
|
||||||
if (!isModalDrawing || !modalCanvasRef.current) return;
|
if (!isModalDrawing || !visibleModalCanvasRef.current || !modalCanvasRef.current) return;
|
||||||
|
|
||||||
const rect = modalCanvasRef.current.getBoundingClientRect();
|
const rect = visibleModalCanvasRef.current.getBoundingClientRect();
|
||||||
const scaleX = modalCanvasRef.current.width / rect.width;
|
const scaleX = visibleModalCanvasRef.current.width / rect.width;
|
||||||
const scaleY = modalCanvasRef.current.height / rect.height;
|
const scaleY = visibleModalCanvasRef.current.height / rect.height;
|
||||||
const x = (e.clientX - rect.left) * scaleX;
|
const x = (e.clientX - rect.left) * scaleX;
|
||||||
const y = (e.clientY - rect.top) * scaleY;
|
const y = (e.clientY - rect.top) * scaleY;
|
||||||
|
|
||||||
const ctx = modalCanvasRef.current.getContext('2d');
|
// Draw on both canvases
|
||||||
|
const visibleCtx = visibleModalCanvasRef.current.getContext('2d');
|
||||||
|
const hiddenCtx = modalCanvasRef.current.getContext('2d');
|
||||||
|
|
||||||
|
[visibleCtx, hiddenCtx].forEach(ctx => {
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.lineTo(x, y);
|
ctx.lineTo(x, y);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update signature data from hidden canvas (consistent size)
|
||||||
|
const dataURL = modalCanvasRef.current.toDataURL('image/png');
|
||||||
|
setCanvasSignatureData(dataURL);
|
||||||
|
onParameterChange('signatureData', dataURL);
|
||||||
|
|
||||||
|
// Also update the small canvas display
|
||||||
|
if (canvasRef.current) {
|
||||||
|
const smallCtx = canvasRef.current.getContext('2d');
|
||||||
|
if (smallCtx) {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
smallCtx.clearRect(0, 0, canvasRef.current!.width, canvasRef.current!.height);
|
||||||
|
smallCtx.drawImage(img, 0, 0, canvasRef.current!.width, canvasRef.current!.height);
|
||||||
|
};
|
||||||
|
img.src = dataURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopModalDrawing = () => {
|
const stopModalDrawing = () => {
|
||||||
@ -140,6 +197,22 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
const ctx = modalCanvasRef.current.getContext('2d');
|
const ctx = modalCanvasRef.current.getContext('2d');
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.clearRect(0, 0, modalCanvasRef.current.width, modalCanvasRef.current.height);
|
ctx.clearRect(0, 0, modalCanvasRef.current.width, modalCanvasRef.current.height);
|
||||||
|
|
||||||
|
// Also clear the main canvas and signature data
|
||||||
|
if (canvasRef.current) {
|
||||||
|
const mainCtx = canvasRef.current.getContext('2d');
|
||||||
|
if (mainCtx) {
|
||||||
|
mainCtx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setCanvasSignatureData(null);
|
||||||
|
onParameterChange('signatureData', undefined);
|
||||||
|
|
||||||
|
// Deactivate signature placement when cleared
|
||||||
|
if (onDeactivateSignature) {
|
||||||
|
onDeactivateSignature();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,6 +254,11 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
if (e.target?.result) {
|
if (e.target?.result) {
|
||||||
console.log('Image loaded, saving to signatureData, length:', (e.target.result as string).length);
|
console.log('Image loaded, saving to signatureData, length:', (e.target.result as string).length);
|
||||||
|
|
||||||
|
// Clear any existing canvas signatures when uploading image
|
||||||
|
setCanvasSignatureData(null);
|
||||||
|
|
||||||
|
// Set the new image as the active signature
|
||||||
setImageSignatureData(e.target.result as string);
|
setImageSignatureData(e.target.result as string);
|
||||||
onParameterChange('signatureData', e.target.result as string);
|
onParameterChange('signatureData', e.target.result as string);
|
||||||
|
|
||||||
@ -194,6 +272,16 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
setSignatureImage(file);
|
setSignatureImage(file);
|
||||||
|
} else if (!file) {
|
||||||
|
// Clear image signature when no file is selected
|
||||||
|
setImageSignatureData(null);
|
||||||
|
if (parameters.signatureType === 'image') {
|
||||||
|
onParameterChange('signatureData', undefined);
|
||||||
|
// Deactivate signature placement when image is removed
|
||||||
|
if (onDeactivateSignature) {
|
||||||
|
onDeactivateSignature();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -203,58 +291,140 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
const ctx = canvasRef.current.getContext('2d');
|
const ctx = canvasRef.current.getContext('2d');
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.strokeStyle = selectedColor;
|
ctx.strokeStyle = selectedColor;
|
||||||
ctx.lineWidth = 2;
|
ctx.lineWidth = penSize;
|
||||||
ctx.lineCap = 'round';
|
ctx.lineCap = 'round';
|
||||||
ctx.lineJoin = 'round';
|
ctx.lineJoin = 'round';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [parameters.signatureType, selectedColor]);
|
}, [parameters.signatureType, selectedColor, penSize]);
|
||||||
|
|
||||||
// Initialize modal canvas when opened
|
// Initialize both canvases - hidden one always exists, main one when in canvas mode
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (modalCanvasRef.current && isModalOpen) {
|
const initCanvas = (canvas: HTMLCanvasElement | null) => {
|
||||||
const ctx = modalCanvasRef.current.getContext('2d');
|
if (!canvas) return;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
ctx.strokeStyle = selectedColor;
|
ctx.strokeStyle = selectedColor;
|
||||||
ctx.lineWidth = 3;
|
ctx.lineWidth = penSize;
|
||||||
ctx.lineCap = 'round';
|
ctx.lineCap = 'round';
|
||||||
ctx.lineJoin = 'round';
|
ctx.lineJoin = 'round';
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (parameters.signatureType === 'canvas') {
|
||||||
|
initCanvas(canvasRef.current);
|
||||||
|
initCanvas(modalCanvasRef.current); // Hidden canvas always available
|
||||||
}
|
}
|
||||||
}, [isModalOpen, selectedColor]);
|
}, [parameters.signatureType, selectedColor, penSize]);
|
||||||
|
|
||||||
|
// Copy main canvas content to hidden modal canvas whenever signature data changes
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (modalCanvasRef.current && canvasSignatureData) {
|
||||||
|
const hiddenCtx = modalCanvasRef.current.getContext('2d');
|
||||||
|
if (hiddenCtx) {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
if (modalCanvasRef.current) {
|
||||||
|
hiddenCtx.clearRect(0, 0, modalCanvasRef.current.width, modalCanvasRef.current.height);
|
||||||
|
hiddenCtx.drawImage(img, 0, 0, modalCanvasRef.current.width, modalCanvasRef.current.height);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
img.src = canvasSignatureData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [canvasSignatureData]);
|
||||||
|
|
||||||
|
|
||||||
// Switch signature data based on mode
|
// Switch signature data based on mode
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (parameters.signatureType === 'canvas' && canvasSignatureData) {
|
if (parameters.signatureType === 'canvas') {
|
||||||
|
if (canvasSignatureData) {
|
||||||
onParameterChange('signatureData', canvasSignatureData);
|
onParameterChange('signatureData', canvasSignatureData);
|
||||||
} else if (parameters.signatureType === 'image' && imageSignatureData) {
|
} else {
|
||||||
|
onParameterChange('signatureData', undefined);
|
||||||
|
}
|
||||||
|
} else if (parameters.signatureType === 'image') {
|
||||||
|
if (imageSignatureData) {
|
||||||
onParameterChange('signatureData', imageSignatureData);
|
onParameterChange('signatureData', imageSignatureData);
|
||||||
|
} else {
|
||||||
|
onParameterChange('signatureData', undefined);
|
||||||
|
}
|
||||||
|
} else if (parameters.signatureType === 'text') {
|
||||||
|
// For text mode, we don't use signatureData - we use signerName directly
|
||||||
|
onParameterChange('signatureData', undefined);
|
||||||
|
} else {
|
||||||
|
// For draw mode, clear signature data
|
||||||
|
onParameterChange('signatureData', undefined);
|
||||||
}
|
}
|
||||||
}, [parameters.signatureType, canvasSignatureData, imageSignatureData, onParameterChange]);
|
}, [parameters.signatureType, canvasSignatureData, imageSignatureData, onParameterChange]);
|
||||||
|
|
||||||
// Auto-activate draw mode when draw type is selected (only trigger on signatureType change)
|
// Initialize draw mode on mount
|
||||||
|
React.useEffect(() => {
|
||||||
|
// Use a ref to track if we've already initialized
|
||||||
|
let isInitialized = false;
|
||||||
|
|
||||||
|
if (parameters.signatureType === 'draw' && onActivateDrawMode && !isInitialized) {
|
||||||
|
// Delay to ensure viewer is ready
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
onActivateDrawMode();
|
||||||
|
isInitialized = true;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}
|
||||||
|
}, []); // Empty dependency - only run on mount
|
||||||
|
|
||||||
|
// Auto-activate draw mode when draw type is selected
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (parameters.signatureType === 'draw') {
|
if (parameters.signatureType === 'draw') {
|
||||||
if (onActivateDrawMode) {
|
if (onActivateDrawMode) {
|
||||||
onActivateDrawMode();
|
onActivateDrawMode();
|
||||||
}
|
}
|
||||||
} else if (parameters.signatureType !== 'draw') {
|
} else {
|
||||||
if (onDeactivateSignature) {
|
if (onDeactivateSignature) {
|
||||||
onDeactivateSignature();
|
onDeactivateSignature();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [parameters.signatureType]); // Only depend on signatureType to avoid loops
|
}, [parameters.signatureType]); // Only depend on signatureType to avoid loops
|
||||||
|
|
||||||
|
// Auto-activate text signature placement when signer name is entered
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (parameters.signatureType === 'text' && parameters.signerName && parameters.signerName.trim() !== '') {
|
||||||
|
if (onActivateSignaturePlacement) {
|
||||||
|
setTimeout(() => {
|
||||||
|
onActivateSignaturePlacement();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
} else if (parameters.signatureType === 'text' && (!parameters.signerName || parameters.signerName.trim() === '')) {
|
||||||
|
if (onDeactivateSignature) {
|
||||||
|
onDeactivateSignature();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [parameters.signatureType, parameters.signerName]); // Remove function dependencies to prevent loops
|
||||||
|
|
||||||
// Update draw settings when color or pen size changes
|
// Update draw settings when color or pen size changes
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
console.log('SignSettings: Draw settings changed - color:', selectedColor, 'penSize:', penSize, 'signatureType:', parameters.signatureType);
|
|
||||||
if (parameters.signatureType === 'draw' && onUpdateDrawSettings) {
|
if (parameters.signatureType === 'draw' && onUpdateDrawSettings) {
|
||||||
console.log('SignSettings: Calling onUpdateDrawSettings');
|
|
||||||
onUpdateDrawSettings(selectedColor, penSize);
|
onUpdateDrawSettings(selectedColor, penSize);
|
||||||
} else {
|
|
||||||
console.log('SignSettings: Not calling onUpdateDrawSettings - signatureType not draw or function not available');
|
|
||||||
}
|
}
|
||||||
}, [selectedColor, penSize, parameters.signatureType, onUpdateDrawSettings]);
|
}, [selectedColor, penSize, parameters.signatureType]); // Remove function dependency to prevent loops
|
||||||
|
|
||||||
|
// Sync font size input with parameter changes
|
||||||
|
React.useEffect(() => {
|
||||||
|
setFontSizeInput((parameters.fontSize || 16).toString());
|
||||||
|
}, [parameters.fontSize]);
|
||||||
|
|
||||||
|
// Update signature config when font settings change
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (parameters.signatureType === 'text' && (parameters.fontFamily || parameters.fontSize)) {
|
||||||
|
// Trigger re-activation of signature placement to apply new font settings
|
||||||
|
if (parameters.signerName && parameters.signerName.trim() !== '' && onActivateSignaturePlacement) {
|
||||||
|
setTimeout(() => {
|
||||||
|
onActivateSignaturePlacement();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [parameters.fontFamily, parameters.fontSize, parameters.signatureType, parameters.signerName]); // Remove function dependency to prevent loops
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
@ -301,7 +471,23 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
right: 8,
|
right: 8,
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
}}
|
}}
|
||||||
onClick={() => setIsModalOpen(true)}
|
onClick={() => {
|
||||||
|
setIsModalOpen(true);
|
||||||
|
// Copy content to modal canvas after a brief delay
|
||||||
|
setTimeout(() => {
|
||||||
|
if (visibleModalCanvasRef.current && modalCanvasRef.current) {
|
||||||
|
const visibleCtx = visibleModalCanvasRef.current.getContext('2d');
|
||||||
|
if (visibleCtx) {
|
||||||
|
visibleCtx.strokeStyle = selectedColor;
|
||||||
|
visibleCtx.lineWidth = penSize;
|
||||||
|
visibleCtx.lineCap = 'round';
|
||||||
|
visibleCtx.lineJoin = 'round';
|
||||||
|
visibleCtx.clearRect(0, 0, visibleModalCanvasRef.current.width, visibleModalCanvasRef.current.height);
|
||||||
|
visibleCtx.drawImage(modalCanvasRef.current, 0, 0, visibleModalCanvasRef.current.width, visibleModalCanvasRef.current.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
title="Expand Canvas"
|
title="Expand Canvas"
|
||||||
>
|
>
|
||||||
@ -345,6 +531,60 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
</Group>
|
</Group>
|
||||||
</Menu.Dropdown>
|
</Menu.Dropdown>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
<Combobox
|
||||||
|
onOptionSubmit={(optionValue) => {
|
||||||
|
const size = parseInt(optionValue);
|
||||||
|
if (!isNaN(size)) {
|
||||||
|
setPenSize(size);
|
||||||
|
setPenSizeInput(optionValue);
|
||||||
|
}
|
||||||
|
penSizeCombobox.closeDropdown();
|
||||||
|
}}
|
||||||
|
store={penSizeCombobox}
|
||||||
|
withinPortal={false}
|
||||||
|
>
|
||||||
|
<Combobox.Target>
|
||||||
|
<TextInput
|
||||||
|
placeholder="Pen size"
|
||||||
|
size="compact-sm"
|
||||||
|
value={penSizeInput}
|
||||||
|
onChange={(event) => {
|
||||||
|
const value = event.currentTarget.value;
|
||||||
|
setPenSizeInput(value);
|
||||||
|
|
||||||
|
const size = parseInt(value);
|
||||||
|
if (!isNaN(size) && size >= 1 && size <= 200) {
|
||||||
|
setPenSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
penSizeCombobox.openDropdown();
|
||||||
|
penSizeCombobox.updateSelectedOptionIndex();
|
||||||
|
}}
|
||||||
|
onClick={() => penSizeCombobox.openDropdown()}
|
||||||
|
onFocus={() => penSizeCombobox.openDropdown()}
|
||||||
|
onBlur={() => {
|
||||||
|
penSizeCombobox.closeDropdown();
|
||||||
|
const size = parseInt(penSizeInput);
|
||||||
|
if (isNaN(size) || size < 1 || size > 200) {
|
||||||
|
setPenSizeInput(penSize.toString());
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
style={{ width: '80px' }}
|
||||||
|
/>
|
||||||
|
</Combobox.Target>
|
||||||
|
|
||||||
|
<Combobox.Dropdown>
|
||||||
|
<Combobox.Options>
|
||||||
|
{['1', '2', '3', '4', '5', '8', '10', '12', '15', '20', '25', '30', '40', '50'].map((size) => (
|
||||||
|
<Combobox.Option value={size} key={size}>
|
||||||
|
{size}px
|
||||||
|
</Combobox.Option>
|
||||||
|
))}
|
||||||
|
</Combobox.Options>
|
||||||
|
</Combobox.Dropdown>
|
||||||
|
</Combobox>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
color="red"
|
color="red"
|
||||||
@ -405,6 +645,79 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Font Selection */}
|
||||||
|
<Select
|
||||||
|
label="Font"
|
||||||
|
value={parameters.fontFamily || 'Helvetica'}
|
||||||
|
onChange={(value) => onParameterChange('fontFamily', value || 'Helvetica')}
|
||||||
|
data={[
|
||||||
|
{ value: 'Helvetica', label: 'Helvetica' },
|
||||||
|
{ value: 'Times-Roman', label: 'Times' },
|
||||||
|
{ value: 'Courier', label: 'Courier' },
|
||||||
|
{ value: 'Arial', label: 'Arial' },
|
||||||
|
{ value: 'Georgia', label: 'Georgia' },
|
||||||
|
]}
|
||||||
|
disabled={disabled}
|
||||||
|
searchable
|
||||||
|
allowDeselect={false}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Font Size */}
|
||||||
|
<Combobox
|
||||||
|
onOptionSubmit={(optionValue) => {
|
||||||
|
setFontSizeInput(optionValue);
|
||||||
|
const size = parseInt(optionValue);
|
||||||
|
if (!isNaN(size)) {
|
||||||
|
onParameterChange('fontSize', size);
|
||||||
|
}
|
||||||
|
fontSizeCombobox.closeDropdown();
|
||||||
|
}}
|
||||||
|
store={fontSizeCombobox}
|
||||||
|
withinPortal={false}
|
||||||
|
>
|
||||||
|
<Combobox.Target>
|
||||||
|
<TextInput
|
||||||
|
label="Font Size"
|
||||||
|
placeholder="Type or select font size (8-72)"
|
||||||
|
value={fontSizeInput}
|
||||||
|
onChange={(event) => {
|
||||||
|
const value = event.currentTarget.value;
|
||||||
|
setFontSizeInput(value);
|
||||||
|
|
||||||
|
// Parse and validate the typed value in real-time
|
||||||
|
const size = parseInt(value);
|
||||||
|
if (!isNaN(size) && size >= 8 && size <= 72) {
|
||||||
|
onParameterChange('fontSize', size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fontSizeCombobox.openDropdown();
|
||||||
|
fontSizeCombobox.updateSelectedOptionIndex();
|
||||||
|
}}
|
||||||
|
onClick={() => fontSizeCombobox.openDropdown()}
|
||||||
|
onFocus={() => fontSizeCombobox.openDropdown()}
|
||||||
|
onBlur={() => {
|
||||||
|
fontSizeCombobox.closeDropdown();
|
||||||
|
// Clean up invalid values on blur
|
||||||
|
const size = parseInt(fontSizeInput);
|
||||||
|
if (isNaN(size) || size < 8 || size > 72) {
|
||||||
|
setFontSizeInput((parameters.fontSize || 16).toString());
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</Combobox.Target>
|
||||||
|
|
||||||
|
<Combobox.Dropdown>
|
||||||
|
<Combobox.Options>
|
||||||
|
{['8', '12', '16', '20', '24', '28', '32', '36', '40', '48'].map((size) => (
|
||||||
|
<Combobox.Option value={size} key={size}>
|
||||||
|
{size}px
|
||||||
|
</Combobox.Option>
|
||||||
|
))}
|
||||||
|
</Combobox.Options>
|
||||||
|
</Combobox.Dropdown>
|
||||||
|
</Combobox>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -414,7 +727,7 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Text fw={500}>Direct PDF Drawing</Text>
|
<Text fw={500}>Direct PDF Drawing</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
Draw signatures and annotations directly on the PDF document. Drawing mode will be activated automatically when you go to the PDF viewer.
|
Draw signatures and annotations directly on the PDF document.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
{/* Drawing Controls */}
|
{/* Drawing Controls */}
|
||||||
@ -440,19 +753,58 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
|
|
||||||
{/* Pen Size */}
|
{/* Pen Size */}
|
||||||
<div style={{ flexGrow: 1, maxWidth: '200px' }}>
|
<div style={{ flexGrow: 1, maxWidth: '200px' }}>
|
||||||
<Text size="sm" fw={500} mb="xs">Pen Size: {penSize}px</Text>
|
<Text size="sm" fw={500} mb="xs">Pen Size</Text>
|
||||||
<Slider
|
<Combobox
|
||||||
value={penSize}
|
onOptionSubmit={(optionValue) => {
|
||||||
onChange={setPenSize}
|
const size = parseInt(optionValue);
|
||||||
min={1}
|
if (!isNaN(size)) {
|
||||||
max={10}
|
setPenSize(size);
|
||||||
step={1}
|
setPenSizeInput(optionValue);
|
||||||
marks={[
|
}
|
||||||
{ value: 1, label: '1' },
|
penSizeCombobox.closeDropdown();
|
||||||
{ value: 5, label: '5' },
|
}}
|
||||||
{ value: 10, label: '10' }
|
store={penSizeCombobox}
|
||||||
]}
|
withinPortal={false}
|
||||||
|
>
|
||||||
|
<Combobox.Target>
|
||||||
|
<TextInput
|
||||||
|
placeholder="Type or select pen size (1-200)"
|
||||||
|
value={penSizeInput}
|
||||||
|
onChange={(event) => {
|
||||||
|
const value = event.currentTarget.value;
|
||||||
|
setPenSizeInput(value);
|
||||||
|
|
||||||
|
const size = parseInt(value);
|
||||||
|
if (!isNaN(size) && size >= 1 && size <= 200) {
|
||||||
|
setPenSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
penSizeCombobox.openDropdown();
|
||||||
|
penSizeCombobox.updateSelectedOptionIndex();
|
||||||
|
}}
|
||||||
|
onClick={() => penSizeCombobox.openDropdown()}
|
||||||
|
onFocus={() => penSizeCombobox.openDropdown()}
|
||||||
|
onBlur={() => {
|
||||||
|
penSizeCombobox.closeDropdown();
|
||||||
|
const size = parseInt(penSizeInput);
|
||||||
|
if (isNaN(size) || size < 1 || size > 200) {
|
||||||
|
setPenSizeInput(penSize.toString());
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
|
</Combobox.Target>
|
||||||
|
|
||||||
|
<Combobox.Dropdown>
|
||||||
|
<Combobox.Options>
|
||||||
|
{['1', '2', '3', '4', '5', '8', '10', '12', '15', '20', '25', '30', '40', '50'].map((size) => (
|
||||||
|
<Combobox.Option value={size} key={size}>
|
||||||
|
{size}px
|
||||||
|
</Combobox.Option>
|
||||||
|
))}
|
||||||
|
</Combobox.Options>
|
||||||
|
</Combobox.Dropdown>
|
||||||
|
</Combobox>
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
@ -464,46 +816,21 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
{(parameters.signatureType === 'canvas' || parameters.signatureType === 'image' || parameters.signatureType === 'text') && (
|
{(parameters.signatureType === 'canvas' || parameters.signatureType === 'image' || parameters.signatureType === 'text') && (
|
||||||
<Alert color="blue" title={t('sign.instructions.title', 'How to add signature')}>
|
<Alert color="blue" title={t('sign.instructions.title', 'How to add signature')}>
|
||||||
<Text size="sm">
|
<Text size="sm">
|
||||||
{parameters.signatureType === 'canvas' && 'Draw your signature in the canvas above. Placement mode will activate automatically, or click the buttons below to control placement.'}
|
{parameters.signatureType === 'canvas' && 'Draw your signature in the canvas above. Placement mode will activate automatically when you finish drawing.'}
|
||||||
{parameters.signatureType === 'image' && 'Upload your signature image above. Placement mode will activate automatically, or click the buttons below to control placement.'}
|
{parameters.signatureType === 'image' && 'Upload your signature image above. Placement mode will activate automatically when the image is loaded.'}
|
||||||
{parameters.signatureType === 'text' && 'Enter your name above. Placement mode will activate automatically, or click the buttons below to control placement.'}
|
{parameters.signatureType === 'text' && 'Enter your name above. Placement mode will activate automatically when you type your name.'}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Group mt="sm" gap="sm">
|
|
||||||
{/* Universal activation button */}
|
|
||||||
{((parameters.signatureType === 'canvas' && parameters.signatureData) ||
|
|
||||||
(parameters.signatureType === 'image' && parameters.signatureData) ||
|
|
||||||
(parameters.signatureType === 'text' && parameters.signerName)) && (
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
if (onActivateSignaturePlacement) {
|
|
||||||
onActivateSignaturePlacement();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
{t('sign.activate', 'Activate Signature Placement')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Universal deactivate button */}
|
|
||||||
<Button
|
|
||||||
variant="subtle"
|
|
||||||
color="red"
|
|
||||||
onClick={() => {
|
|
||||||
if (onDeactivateSignature) {
|
|
||||||
onDeactivateSignature();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
{t('sign.deactivate', 'Stop Placing Signatures')}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
|
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Hidden canvas for modal synchronization - always exists */}
|
||||||
|
<canvas
|
||||||
|
ref={modalCanvasRef}
|
||||||
|
width={800}
|
||||||
|
height={400}
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Modal for larger signature canvas */}
|
{/* Modal for larger signature canvas */}
|
||||||
<Modal
|
<Modal
|
||||||
opened={isModalOpen}
|
opened={isModalOpen}
|
||||||
@ -513,10 +840,12 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
centered
|
centered
|
||||||
>
|
>
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
{/* Color picker */}
|
{/* Color and Pen Size picker */}
|
||||||
<Paper withBorder p="sm">
|
<Paper withBorder p="sm">
|
||||||
<Group gap="sm" align="center">
|
<Group gap="lg" align="flex-end">
|
||||||
<Text size="sm" fw={500}>Color:</Text>
|
<div>
|
||||||
|
<Text size="sm" fw={500} mb="xs">Color:</Text>
|
||||||
|
<Group gap="xs">
|
||||||
{['#000000', '#0066cc', '#cc0000', '#cc6600', '#009900', '#6600cc'].map((color) => (
|
{['#000000', '#0066cc', '#cc0000', '#cc6600', '#009900', '#6600cc'].map((color) => (
|
||||||
<ColorSwatch
|
<ColorSwatch
|
||||||
key={color}
|
key={color}
|
||||||
@ -527,11 +856,69 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Group>
|
</Group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Text size="sm" fw={500} mb="xs">Pen Size:</Text>
|
||||||
|
<Combobox
|
||||||
|
onOptionSubmit={(optionValue) => {
|
||||||
|
const size = parseInt(optionValue);
|
||||||
|
if (!isNaN(size)) {
|
||||||
|
setPenSize(size);
|
||||||
|
setPenSizeInput(optionValue);
|
||||||
|
}
|
||||||
|
penSizeCombobox.closeDropdown();
|
||||||
|
}}
|
||||||
|
store={penSizeCombobox}
|
||||||
|
withinPortal={false}
|
||||||
|
>
|
||||||
|
<Combobox.Target>
|
||||||
|
<TextInput
|
||||||
|
placeholder="Pen size"
|
||||||
|
size="sm"
|
||||||
|
value={penSizeInput}
|
||||||
|
onChange={(event) => {
|
||||||
|
const value = event.currentTarget.value;
|
||||||
|
setPenSizeInput(value);
|
||||||
|
|
||||||
|
const size = parseInt(value);
|
||||||
|
if (!isNaN(size) && size >= 1 && size <= 200) {
|
||||||
|
setPenSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
penSizeCombobox.openDropdown();
|
||||||
|
penSizeCombobox.updateSelectedOptionIndex();
|
||||||
|
}}
|
||||||
|
onClick={() => penSizeCombobox.openDropdown()}
|
||||||
|
onFocus={() => penSizeCombobox.openDropdown()}
|
||||||
|
onBlur={() => {
|
||||||
|
penSizeCombobox.closeDropdown();
|
||||||
|
const size = parseInt(penSizeInput);
|
||||||
|
if (isNaN(size) || size < 1 || size > 200) {
|
||||||
|
setPenSizeInput(penSize.toString());
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style={{ width: '100px' }}
|
||||||
|
/>
|
||||||
|
</Combobox.Target>
|
||||||
|
|
||||||
|
<Combobox.Dropdown>
|
||||||
|
<Combobox.Options>
|
||||||
|
{['1', '2', '3', '4', '5', '8', '10', '12', '15', '20', '25', '30', '40', '50'].map((size) => (
|
||||||
|
<Combobox.Option value={size} key={size}>
|
||||||
|
{size}px
|
||||||
|
</Combobox.Option>
|
||||||
|
))}
|
||||||
|
</Combobox.Options>
|
||||||
|
</Combobox.Dropdown>
|
||||||
|
</Combobox>
|
||||||
|
</div>
|
||||||
|
</Group>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
<Paper withBorder p="md">
|
<Paper withBorder p="md">
|
||||||
<canvas
|
<canvas
|
||||||
ref={modalCanvasRef}
|
ref={visibleModalCanvasRef}
|
||||||
width={800}
|
width={800}
|
||||||
height={400}
|
height={400}
|
||||||
style={{
|
style={{
|
||||||
|
@ -74,7 +74,10 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI, SignatureAPIBridgePro
|
|||||||
if (activeTool && activeTool.id === 'ink') {
|
if (activeTool && activeTool.id === 'ink') {
|
||||||
annotationApi.setToolDefaults('ink', {
|
annotationApi.setToolDefaults('ink', {
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
thickness: 2
|
thickness: 2,
|
||||||
|
lineWidth: 2,
|
||||||
|
strokeWidth: 2,
|
||||||
|
width: 2
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -86,19 +89,62 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI, SignatureAPIBridgePro
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('Signature type:', signatureConfig.signatureType);
|
console.log('Signature type:', signatureConfig.signatureType);
|
||||||
|
console.log('Font settings:', { fontFamily: signatureConfig.fontFamily, fontSize: signatureConfig.fontSize });
|
||||||
if (signatureConfig.signatureType === 'text' && signatureConfig.signerName) {
|
if (signatureConfig.signatureType === 'text' && signatureConfig.signerName) {
|
||||||
console.log('Activating freetext tool');
|
console.log('Trying different text tool names');
|
||||||
// Use freetext tool for text signatures
|
|
||||||
annotationApi.setActiveTool('freetext');
|
// Try different tool names for text annotations
|
||||||
const activeTool = annotationApi.getActiveTool();
|
const textToolNames = ['freetext', 'text', 'textbox', 'annotation-text'];
|
||||||
console.log('Freetext tool activated:', activeTool);
|
let activatedTool = null;
|
||||||
if (activeTool && activeTool.id === 'freetext') {
|
|
||||||
annotationApi.setToolDefaults('freetext', {
|
for (const toolName of textToolNames) {
|
||||||
|
console.log(`Trying tool: ${toolName}`);
|
||||||
|
annotationApi.setActiveTool(toolName);
|
||||||
|
const tool = annotationApi.getActiveTool();
|
||||||
|
console.log(`Tool result for ${toolName}:`, tool);
|
||||||
|
|
||||||
|
if (tool && tool.id === toolName) {
|
||||||
|
activatedTool = tool;
|
||||||
|
console.log(`Successfully activated ${toolName}`);
|
||||||
|
annotationApi.setToolDefaults(toolName, {
|
||||||
contents: signatureConfig.signerName,
|
contents: signatureConfig.signerName,
|
||||||
fontSize: 16,
|
fontSize: signatureConfig.fontSize || 16,
|
||||||
fontFamily: PdfStandardFont.Helvetica,
|
fontFamily: signatureConfig.fontFamily === 'Times-Roman' ? PdfStandardFont.Times_Roman :
|
||||||
|
signatureConfig.fontFamily === 'Courier' ? PdfStandardFont.Courier :
|
||||||
|
PdfStandardFont.Helvetica,
|
||||||
fontColor: '#000000',
|
fontColor: '#000000',
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activatedTool) {
|
||||||
|
console.log('No text tool could be activated, trying stamp as fallback');
|
||||||
|
// Fallback: create a simple text image as stamp
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (ctx) {
|
||||||
|
const fontSize = signatureConfig.fontSize || 16;
|
||||||
|
const fontFamily = signatureConfig.fontFamily || 'Helvetica';
|
||||||
|
|
||||||
|
canvas.width = Math.max(200, signatureConfig.signerName.length * fontSize * 0.6);
|
||||||
|
canvas.height = fontSize + 20;
|
||||||
|
ctx.fillStyle = '#000000';
|
||||||
|
ctx.font = `${fontSize}px ${fontFamily}`;
|
||||||
|
ctx.textAlign = 'left';
|
||||||
|
ctx.textBaseline = 'middle';
|
||||||
|
ctx.fillText(signatureConfig.signerName, 10, canvas.height / 2);
|
||||||
|
const dataURL = canvas.toDataURL();
|
||||||
|
|
||||||
|
annotationApi.setActiveTool('stamp');
|
||||||
|
const stampTool = annotationApi.getActiveTool();
|
||||||
|
if (stampTool && stampTool.id === 'stamp') {
|
||||||
|
annotationApi.setToolDefaults('stamp', {
|
||||||
|
imageSrc: dataURL,
|
||||||
|
subject: `Text Signature - ${signatureConfig.signerName}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (signatureConfig.signatureData) {
|
} else if (signatureConfig.signatureData) {
|
||||||
console.log('Activating stamp tool');
|
console.log('Activating stamp tool');
|
||||||
@ -119,26 +165,22 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI, SignatureAPIBridgePro
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateDrawSettings: (color: string, size: number) => {
|
updateDrawSettings: (color: string, size: number) => {
|
||||||
console.log('SignatureAPIBridge.updateDrawSettings called with color:', color, 'size:', size);
|
if (!annotationApi) return;
|
||||||
if (!annotationApi) {
|
|
||||||
console.log('No annotationApi available for updateDrawSettings');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always update ink tool defaults regardless of current tool
|
// Always update ink tool defaults - use multiple property names for compatibility
|
||||||
console.log('Setting ink tool defaults');
|
|
||||||
annotationApi.setToolDefaults('ink', {
|
annotationApi.setToolDefaults('ink', {
|
||||||
color: color,
|
color: color,
|
||||||
thickness: size
|
thickness: size,
|
||||||
|
lineWidth: size,
|
||||||
|
strokeWidth: size,
|
||||||
|
width: size
|
||||||
});
|
});
|
||||||
|
|
||||||
// If ink tool is currently active, reactivate it to apply settings immediately
|
// Force reactivate ink tool to ensure new settings take effect
|
||||||
const activeTool = annotationApi.getActiveTool();
|
annotationApi.setActiveTool(null); // Deactivate first
|
||||||
console.log('Current active tool:', activeTool);
|
setTimeout(() => {
|
||||||
if (activeTool && activeTool.id === 'ink') {
|
annotationApi.setActiveTool('ink'); // Reactivate with new settings
|
||||||
console.log('Reactivating ink tool to apply new settings');
|
}, 50);
|
||||||
annotationApi.setActiveTool('ink');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
deactivateTools: () => {
|
deactivateTools: () => {
|
||||||
|
@ -76,6 +76,7 @@ export const SignatureProvider: React.FC<{ children: ReactNode }> = ({ children
|
|||||||
|
|
||||||
const activateSignaturePlacementMode = useCallback(() => {
|
const activateSignaturePlacementMode = useCallback(() => {
|
||||||
console.log('SignatureContext.activateSignaturePlacementMode called');
|
console.log('SignatureContext.activateSignaturePlacementMode called');
|
||||||
|
console.log('Current signature config:', state.signatureConfig);
|
||||||
if (signatureApiRef.current) {
|
if (signatureApiRef.current) {
|
||||||
console.log('Calling signatureApiRef.current.activateSignaturePlacementMode()');
|
console.log('Calling signatureApiRef.current.activateSignaturePlacementMode()');
|
||||||
signatureApiRef.current.activateSignaturePlacementMode();
|
signatureApiRef.current.activateSignaturePlacementMode();
|
||||||
@ -86,12 +87,8 @@ export const SignatureProvider: React.FC<{ children: ReactNode }> = ({ children
|
|||||||
}, [state.signatureConfig, setPlacementMode]);
|
}, [state.signatureConfig, setPlacementMode]);
|
||||||
|
|
||||||
const updateDrawSettings = useCallback((color: string, size: number) => {
|
const updateDrawSettings = useCallback((color: string, size: number) => {
|
||||||
console.log('SignatureContext.updateDrawSettings called with color:', color, 'size:', size);
|
|
||||||
console.log('signatureApiRef.current available:', !!signatureApiRef.current);
|
|
||||||
if (signatureApiRef.current) {
|
if (signatureApiRef.current) {
|
||||||
signatureApiRef.current.updateDrawSettings(color, size);
|
signatureApiRef.current.updateDrawSettings(color, size);
|
||||||
} else {
|
|
||||||
console.log('signatureApiRef.current is null - cannot update draw settings');
|
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ export interface SignParameters {
|
|||||||
reason?: string;
|
reason?: string;
|
||||||
location?: string;
|
location?: string;
|
||||||
signerName?: string;
|
signerName?: string;
|
||||||
|
fontFamily?: string;
|
||||||
|
fontSize?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_PARAMETERS: SignParameters = {
|
export const DEFAULT_PARAMETERS: SignParameters = {
|
||||||
@ -22,6 +24,8 @@ export const DEFAULT_PARAMETERS: SignParameters = {
|
|||||||
reason: 'Document signing',
|
reason: 'Document signing',
|
||||||
location: 'Digital',
|
location: 'Digital',
|
||||||
signerName: '',
|
signerName: '',
|
||||||
|
fontFamily: 'Helvetica',
|
||||||
|
fontSize: 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateSignParameters = (parameters: SignParameters): boolean => {
|
const validateSignParameters = (parameters: SignParameters): boolean => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user