Rescue Paperjet v1 implementation

This commit is contained in:
Elijah 2026-08-14 21:05:22 -07:00
parent 7ff5c8130d
commit db9e2ca51b
83 changed files with 6186 additions and 3894 deletions

View file

@ -6,11 +6,18 @@ import type { Annotation, SignatureAnnotation, SignatureDrawProps, SignatureType
import { screenRectToPdf, pdfRectToScreen } from '../../../lib/coords';
import type { ViewportParams } from '../../../lib/coords';
type SignatureProps = SignatureDrawProps | SignatureTypeProps;
type FabricSignatureObject = fabric.FabricObject & {
id?: string;
annotationType?: string;
annotationProps?: SignatureProps;
};
let previewObj: fabric.FabricObject | null = null;
let currentPreviewCanvas: fabric.Canvas | null = null;
let isCreatingPreview = false;
const createPreview = async (canvas: fabric.Canvas, vp: ViewportParams, props: any) => {
const createPreview = async (canvas: fabric.Canvas, vp: ViewportParams, props: SignatureProps) => {
isCreatingPreview = true;
const storeState = useEditorStore.getState();
if (props.mode === 'draw') {
@ -23,11 +30,13 @@ const createPreview = async (canvas: fabric.Canvas, vp: ViewportParams, props: a
}
img.set({ originX: 'center', originY: 'center', opacity: 0.5, evented: false });
previewObj = img;
} catch (e) {}
} catch {
previewObj = null;
}
} else {
previewObj = new fabric.Text(props.text, {
fontFamily: props.fontFamily,
fontSize: 48 * vp.scale * (vp.dpr || 1),
fontSize: 48 * vp.scale,
fill: props.color,
originX: 'center',
originY: 'center',
@ -61,7 +70,7 @@ export const SignatureTool: ToolHandler = {
isCreatingPreview = false;
},
onPointerMove: (e: any, canvas: fabric.Canvas, vp: ViewportParams, _pageNumber: number) => {
onPointerMove: (e: fabric.TPointerEventInfo, canvas: fabric.Canvas, vp: ViewportParams) => {
const props = useEditorStore.getState().pendingSignatureProps;
if (!props) return;
@ -86,7 +95,7 @@ export const SignatureTool: ToolHandler = {
}
},
onPointerDown: async (e: any, canvas: fabric.Canvas, vp: ViewportParams, pageNumber: number) => {
onPointerDown: async (e: fabric.TPointerEventInfo, canvas: fabric.Canvas, vp: ViewportParams, pageNumber: number) => {
if (e.target && e.target !== previewObj) return;
const storeState = useEditorStore.getState();
@ -120,7 +129,7 @@ export const SignatureTool: ToolHandler = {
originY: 'center',
});
// We set id on the object so it can be identified
(img as any).id = uuidv4();
(img as FabricSignatureObject).id = uuidv4();
fabricObj = img;
} catch (err) {
console.error("Failed to load signature image", err);
@ -132,12 +141,12 @@ export const SignatureTool: ToolHandler = {
left: pointer.x,
top: pointer.y,
fontFamily: typeProps.fontFamily,
fontSize: 48 * vp.scale * (vp.dpr || 1),
fontSize: 48 * vp.scale,
fill: typeProps.color,
originX: 'center',
originY: 'center',
});
(textObj as any).id = uuidv4();
(textObj as FabricSignatureObject).id = uuidv4();
fabricObj = textObj;
}
@ -150,8 +159,9 @@ export const SignatureTool: ToolHandler = {
padding: 5,
});
(fabricObj as any).annotationType = 'signature';
(fabricObj as any).annotationProps = props;
const annotatedObject = fabricObj as FabricSignatureObject;
annotatedObject.annotationType = 'signature';
annotatedObject.annotationProps = props;
canvas.add(fabricObj);
canvas.setActiveObject(fabricObj);
@ -167,7 +177,7 @@ export const SignatureTool: ToolHandler = {
}, vp);
const annotation: SignatureAnnotation = {
id: (fabricObj as any).id,
id: annotatedObject.id as string,
page: pageNumber,
type: 'signature',
rect: pdfRect,
@ -186,7 +196,7 @@ export const SignatureTool: ToolHandler = {
},
renderToFabric: async (annotation: Annotation, canvas: fabric.Canvas, vp: ViewportParams) => {
if (annotation.type !== 'signature') return null;
if (annotation.type !== 'signature') return;
const sigAnn = annotation as SignatureAnnotation;
const screenRect = pdfRectToScreen(sigAnn.rect, vp);
@ -199,19 +209,23 @@ export const SignatureTool: ToolHandler = {
img.set({
left: screenRect.x,
top: screenRect.y,
originX: 'left',
originY: 'top',
scaleX: screenRect.width / img.width!,
scaleY: screenRect.height / img.height!,
});
fabricObj = img;
} catch (e) {
console.error("Failed to load signature asset", e);
return null;
return;
}
} else {
const typeProps = sigAnn.props as SignatureTypeProps;
fabricObj = new fabric.Text(typeProps.text, {
left: screenRect.x,
top: screenRect.y,
originX: 'left',
originY: 'top',
fontFamily: typeProps.fontFamily,
fill: typeProps.color,
});
@ -222,17 +236,18 @@ export const SignatureTool: ToolHandler = {
});
}
const annotatedObject = fabricObj as FabricSignatureObject;
annotatedObject.id = sigAnn.id;
annotatedObject.annotationType = 'signature';
annotatedObject.annotationProps = sigAnn.props;
fabricObj.set({
id: sigAnn.id,
annotationType: 'signature',
annotationProps: sigAnn.props,
transparentCorners: false,
cornerColor: '#3b82f6',
cornerStrokeColor: '#3b82f6',
borderColor: '#3b82f6',
cornerSize: 8,
padding: 5,
} as any);
});
canvas.add(fabricObj);
}