Delete signature

This commit is contained in:
Reece Browne 2025-09-23 18:16:21 +01:00
parent fc2f34ee15
commit bac61c7e9e
4 changed files with 88 additions and 7 deletions

View File

@ -461,6 +461,7 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
/> />
</div> </div>
{/* Signature Creation based on type */} {/* Signature Creation based on type */}
{parameters.signatureType === 'canvas' && ( {parameters.signatureType === 'canvas' && (
<Paper withBorder p="md"> <Paper withBorder p="md">

View File

@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState, useRef } from 'react';
import { createPluginRegistration } from '@embedpdf/core'; import { createPluginRegistration } from '@embedpdf/core';
import { EmbedPDF } from '@embedpdf/core/react'; import { EmbedPDF } from '@embedpdf/core/react';
import { usePdfiumEngine } from '@embedpdf/engines/react'; import { usePdfiumEngine } from '@embedpdf/engines/react';
@ -46,6 +46,7 @@ interface LocalEmbedPDFProps {
export function LocalEmbedPDF({ file, url, enableSignature = false, onSignatureAdded, signatureApiRef }: LocalEmbedPDFProps) { export function LocalEmbedPDF({ file, url, enableSignature = false, onSignatureAdded, signatureApiRef }: LocalEmbedPDFProps) {
const [pdfUrl, setPdfUrl] = useState<string | null>(null); const [pdfUrl, setPdfUrl] = useState<string | null>(null);
const [annotations, setAnnotations] = useState<Array<{id: string, pageIndex: number, rect: any}>>([]);
// Convert File to URL if needed // Convert File to URL if needed
useEffect(() => { useEffect(() => {
@ -217,14 +218,34 @@ export function LocalEmbedPDF({ file, url, enableSignature = false, onSignatureA
}, },
}); });
// Listen for annotation events to notify parent component // Listen for annotation events to track annotations and notify parent
if (onSignatureAdded) { annotationApi.onAnnotationEvent((event: any) => {
annotationApi.onAnnotationEvent((event: any) => { if (event.type === 'create' && event.committed) {
if (event.type === 'create' && event.committed) { // Add to annotations list
setAnnotations(prev => [...prev, {
id: event.annotation.id,
pageIndex: event.pageIndex,
rect: event.annotation.rect
}]);
// Notify parent if callback provided
if (onSignatureAdded) {
onSignatureAdded(event.annotation); onSignatureAdded(event.annotation);
} }
}); } else if (event.type === 'delete' && event.committed) {
} // Remove from annotations list
setAnnotations(prev => prev.filter(ann => ann.id !== event.annotation.id));
} else if (event.type === 'loaded') {
// Handle initial load of annotations
const loadedAnnotations = event.annotations || [];
setAnnotations(loadedAnnotations.map((ann: any) => ({
id: ann.id,
pageIndex: ann.pageIndex || 0,
rect: ann.rect
})));
}
});
} : undefined} } : undefined}
> >
<ZoomAPIBridge /> <ZoomAPIBridge />
@ -297,6 +318,7 @@ export function LocalEmbedPDF({ file, url, enableSignature = false, onSignatureA
)} )}
/> />
</Viewport> </Viewport>
</GlobalPointerProvider> </GlobalPointerProvider>
</EmbedPDF> </EmbedPDF>
</div> </div>

View File

@ -9,6 +9,8 @@ export interface SignatureAPI {
addTextSignature: (text: string, x: number, y: number, pageIndex: number) => void; addTextSignature: (text: string, x: number, y: number, pageIndex: number) => void;
activateDrawMode: () => void; activateDrawMode: () => void;
activateSignaturePlacementMode: () => void; activateSignaturePlacementMode: () => void;
activateDeleteMode: () => void;
deleteAnnotation: (annotationId: string, pageIndex: number) => void;
updateDrawSettings: (color: string, size: number) => void; updateDrawSettings: (color: string, size: number) => void;
deactivateTools: () => void; deactivateTools: () => void;
applySignatureFromParameters: (params: SignParameters) => void; applySignatureFromParameters: (params: SignParameters) => void;
@ -20,6 +22,30 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI, SignatureAPIBridgePro
const { provides: annotationApi } = useAnnotationCapability(); const { provides: annotationApi } = useAnnotationCapability();
const { signatureConfig } = useSignature(); const { signatureConfig } = useSignature();
// Enable keyboard deletion of selected annotations
useEffect(() => {
if (!annotationApi) return;
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Delete' || event.key === 'Backspace') {
const selectedAnnotation = annotationApi.getSelectedAnnotation?.();
if (selectedAnnotation) {
const annotation = selectedAnnotation as any;
const pageIndex = annotation.object?.pageIndex || 0;
const id = annotation.object?.id;
if (id) {
annotationApi.deleteAnnotation(pageIndex, id);
}
}
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [annotationApi]);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
addImageSignature: (signatureData: string, x: number, y: number, width: number, height: number, pageIndex: number) => { addImageSignature: (signatureData: string, x: number, y: number, width: number, height: number, pageIndex: number) => {
if (!annotationApi) return; if (!annotationApi) return;
@ -183,6 +209,19 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI, SignatureAPIBridgePro
}, 50); }, 50);
}, },
activateDeleteMode: () => {
if (!annotationApi) return;
// Activate selection tool to allow selecting and deleting annotations
// Users can click annotations to select them, then press Delete key or right-click to delete
annotationApi.setActiveTool('select');
},
deleteAnnotation: (annotationId: string, pageIndex: number) => {
if (!annotationApi) return;
// Delete specific annotation by ID
annotationApi.deleteAnnotation(pageIndex, annotationId);
},
deactivateTools: () => { deactivateTools: () => {
if (!annotationApi) return; if (!annotationApi) return;
annotationApi.setActiveTool(null); annotationApi.setActiveTool(null);
@ -208,6 +247,11 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI, SignatureAPIBridgePro
id: uuidV4(), id: uuidV4(),
created: new Date(), created: new Date(),
}); });
// Switch to select mode after placing signature so it can be easily deleted
setTimeout(() => {
annotationApi.setActiveTool('select');
}, 100);
} }
break; break;
@ -231,6 +275,11 @@ export const SignatureAPIBridge = forwardRef<SignatureAPI, SignatureAPIBridgePro
id: uuidV4(), id: uuidV4(),
created: new Date(), created: new Date(),
}); });
// Switch to select mode after placing signature so it can be easily deleted
setTimeout(() => {
annotationApi.setActiveTool('select');
}, 100);
} }
break; break;

View File

@ -17,6 +17,7 @@ interface SignatureActions {
activateDrawMode: () => void; activateDrawMode: () => void;
deactivateDrawMode: () => void; deactivateDrawMode: () => void;
activateSignaturePlacementMode: () => void; activateSignaturePlacementMode: () => void;
activateDeleteMode: () => void;
updateDrawSettings: (color: string, size: number) => void; updateDrawSettings: (color: string, size: number) => void;
} }
@ -86,6 +87,13 @@ export const SignatureProvider: React.FC<{ children: ReactNode }> = ({ children
} }
}, [state.signatureConfig, setPlacementMode]); }, [state.signatureConfig, setPlacementMode]);
const activateDeleteMode = useCallback(() => {
if (signatureApiRef.current) {
signatureApiRef.current.activateDeleteMode();
setPlacementMode(true);
}
}, [setPlacementMode]);
const updateDrawSettings = useCallback((color: string, size: number) => { const updateDrawSettings = useCallback((color: string, size: number) => {
if (signatureApiRef.current) { if (signatureApiRef.current) {
signatureApiRef.current.updateDrawSettings(color, size); signatureApiRef.current.updateDrawSettings(color, size);
@ -103,6 +111,7 @@ export const SignatureProvider: React.FC<{ children: ReactNode }> = ({ children
activateDrawMode, activateDrawMode,
deactivateDrawMode, deactivateDrawMode,
activateSignaturePlacementMode, activateSignaturePlacementMode,
activateDeleteMode,
updateDrawSettings, updateDrawSettings,
}; };