mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
Feature/annotations (#5260)
This commit is contained in:
@@ -38,8 +38,9 @@ import { SearchAPIBridge } from '@app/components/viewer/SearchAPIBridge';
|
||||
import { ThumbnailAPIBridge } from '@app/components/viewer/ThumbnailAPIBridge';
|
||||
import { RotateAPIBridge } from '@app/components/viewer/RotateAPIBridge';
|
||||
import { SignatureAPIBridge } from '@app/components/viewer/SignatureAPIBridge';
|
||||
import { AnnotationAPIBridge } from '@app/components/viewer/AnnotationAPIBridge';
|
||||
import { HistoryAPIBridge } from '@app/components/viewer/HistoryAPIBridge';
|
||||
import type { SignatureAPI, HistoryAPI } from '@app/components/viewer/viewerTypes';
|
||||
import type { SignatureAPI, AnnotationAPI, HistoryAPI } from '@app/components/viewer/viewerTypes';
|
||||
import { ExportAPIBridge } from '@app/components/viewer/ExportAPIBridge';
|
||||
import { BookmarkAPIBridge } from '@app/components/viewer/BookmarkAPIBridge';
|
||||
import { PrintAPIBridge } from '@app/components/viewer/PrintAPIBridge';
|
||||
@@ -55,10 +56,11 @@ interface LocalEmbedPDFProps {
|
||||
showBakedAnnotations?: boolean;
|
||||
onSignatureAdded?: (annotation: any) => void;
|
||||
signatureApiRef?: React.RefObject<SignatureAPI>;
|
||||
annotationApiRef?: React.RefObject<AnnotationAPI>;
|
||||
historyApiRef?: React.RefObject<HistoryAPI>;
|
||||
}
|
||||
|
||||
export function LocalEmbedPDF({ file, url, enableAnnotations = false, showBakedAnnotations = true, onSignatureAdded, signatureApiRef, historyApiRef }: LocalEmbedPDFProps) {
|
||||
export function LocalEmbedPDF({ file, url, enableAnnotations = false, showBakedAnnotations = true, onSignatureAdded, signatureApiRef, annotationApiRef, historyApiRef }: LocalEmbedPDFProps) {
|
||||
const { t } = useTranslation();
|
||||
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
|
||||
const [, setAnnotations] = useState<Array<{id: string, pageIndex: number, rect: any}>>([]);
|
||||
@@ -123,10 +125,8 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, showBakedA
|
||||
selectAfterCreate: true,
|
||||
}),
|
||||
|
||||
// Register pan plugin (depends on Viewport, InteractionManager)
|
||||
createPluginRegistration(PanPluginPackage, {
|
||||
defaultMode: 'mobile', // Try mobile mode which might be more permissive
|
||||
}),
|
||||
// Register pan plugin (depends on Viewport, InteractionManager) - keep disabled to prevent drag panning
|
||||
createPluginRegistration(PanPluginPackage, {}),
|
||||
|
||||
// Register zoom plugin with configuration
|
||||
createPluginRegistration(ZoomPluginPackage, {
|
||||
@@ -252,7 +252,315 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, showBakedA
|
||||
if (!annotationApi) return;
|
||||
|
||||
if (enableAnnotations) {
|
||||
annotationApi.addTool({
|
||||
const ensureTool = (tool: any) => {
|
||||
const existing = annotationApi.getTool?.(tool.id);
|
||||
if (!existing) {
|
||||
annotationApi.addTool(tool);
|
||||
}
|
||||
};
|
||||
|
||||
ensureTool({
|
||||
id: 'highlight',
|
||||
name: 'Highlight',
|
||||
interaction: { exclusive: true, cursor: 'text', textSelection: true },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.HIGHLIGHT ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.HIGHLIGHT,
|
||||
color: '#ffd54f',
|
||||
opacity: 0.6,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'underline',
|
||||
name: 'Underline',
|
||||
interaction: { exclusive: true, cursor: 'text', textSelection: true },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.UNDERLINE ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.UNDERLINE,
|
||||
color: '#ffb300',
|
||||
opacity: 1,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'strikeout',
|
||||
name: 'Strikeout',
|
||||
interaction: { exclusive: true, cursor: 'text', textSelection: true },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.STRIKEOUT ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.STRIKEOUT,
|
||||
color: '#e53935',
|
||||
opacity: 1,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'squiggly',
|
||||
name: 'Squiggly',
|
||||
interaction: { exclusive: true, cursor: 'text', textSelection: true },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.SQUIGGLY ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.SQUIGGLY,
|
||||
color: '#00acc1',
|
||||
opacity: 1,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'ink',
|
||||
name: 'Pen',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.INK ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.INK,
|
||||
color: '#1f2933',
|
||||
opacity: 1,
|
||||
borderWidth: 2,
|
||||
lineWidth: 2,
|
||||
strokeWidth: 2,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'inkHighlighter',
|
||||
name: 'Ink Highlighter',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.INK && annotation.color === '#ffd54f' ? 8 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.INK,
|
||||
color: '#ffd54f',
|
||||
opacity: 0.5,
|
||||
borderWidth: 6,
|
||||
lineWidth: 6,
|
||||
strokeWidth: 6,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'square',
|
||||
name: 'Square',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.SQUARE ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.SQUARE,
|
||||
color: '#0000ff', // fill color (blue)
|
||||
strokeColor: '#cf5b5b', // border color (reddish pink)
|
||||
opacity: 0.5,
|
||||
borderWidth: 1,
|
||||
strokeWidth: 1,
|
||||
lineWidth: 1,
|
||||
},
|
||||
clickBehavior: {
|
||||
enabled: true,
|
||||
defaultSize: { width: 120, height: 90 },
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: true,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'circle',
|
||||
name: 'Circle',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.CIRCLE ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.CIRCLE,
|
||||
color: '#0000ff', // fill color (blue)
|
||||
strokeColor: '#cf5b5b', // border color (reddish pink)
|
||||
opacity: 0.5,
|
||||
borderWidth: 1,
|
||||
strokeWidth: 1,
|
||||
lineWidth: 1,
|
||||
},
|
||||
clickBehavior: {
|
||||
enabled: true,
|
||||
defaultSize: { width: 100, height: 100 },
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: true,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'line',
|
||||
name: 'Line',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.LINE ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.LINE,
|
||||
color: '#1565c0',
|
||||
opacity: 1,
|
||||
borderWidth: 2,
|
||||
strokeWidth: 2,
|
||||
lineWidth: 2,
|
||||
},
|
||||
clickBehavior: {
|
||||
enabled: true,
|
||||
defaultLength: 120,
|
||||
defaultAngle: 0,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: true,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'lineArrow',
|
||||
name: 'Arrow',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.LINE && (annotation.endStyle === 'ClosedArrow' || annotation.lineEndingStyles?.end === 'ClosedArrow') ? 9 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.LINE,
|
||||
color: '#1565c0',
|
||||
opacity: 1,
|
||||
borderWidth: 2,
|
||||
startStyle: 'None',
|
||||
endStyle: 'ClosedArrow',
|
||||
lineEndingStyles: { start: 'None', end: 'ClosedArrow' },
|
||||
},
|
||||
clickBehavior: {
|
||||
enabled: true,
|
||||
defaultLength: 120,
|
||||
defaultAngle: 0,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: true,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'polyline',
|
||||
name: 'Polyline',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.POLYLINE ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.POLYLINE,
|
||||
color: '#1565c0',
|
||||
opacity: 1,
|
||||
borderWidth: 2,
|
||||
},
|
||||
clickBehavior: {
|
||||
enabled: true,
|
||||
finishOnDoubleClick: true,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: true,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'polygon',
|
||||
name: 'Polygon',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.POLYGON ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.POLYGON,
|
||||
color: '#0000ff', // fill color (blue)
|
||||
strokeColor: '#cf5b5b', // border color (reddish pink)
|
||||
opacity: 0.5,
|
||||
borderWidth: 1,
|
||||
},
|
||||
clickBehavior: {
|
||||
enabled: true,
|
||||
finishOnDoubleClick: true,
|
||||
defaultSize: { width: 140, height: 100 },
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: true,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'text',
|
||||
name: 'Text',
|
||||
interaction: { exclusive: true, cursor: 'text' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.FREETEXT ? 10 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.FREETEXT,
|
||||
textColor: '#111111',
|
||||
fontSize: 14,
|
||||
fontFamily: 'Helvetica',
|
||||
opacity: 1,
|
||||
interiorColor: '#fffef7',
|
||||
contents: 'Text',
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'note',
|
||||
name: 'Note',
|
||||
interaction: { exclusive: true, cursor: 'pointer' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.FREETEXT ? 8 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.FREETEXT,
|
||||
textColor: '#1b1b1b',
|
||||
color: '#ffa000',
|
||||
interiorColor: '#fff8e1',
|
||||
opacity: 1,
|
||||
contents: 'Note',
|
||||
fontSize: 12,
|
||||
},
|
||||
clickBehavior: {
|
||||
enabled: true,
|
||||
defaultSize: { width: 160, height: 100 },
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: false,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'stamp',
|
||||
name: 'Image Stamp',
|
||||
interaction: { exclusive: false, cursor: 'copy' },
|
||||
matchScore: (annotation: any) => (annotation.type === PdfAnnotationSubtype.STAMP ? 5 : 0),
|
||||
defaults: {
|
||||
type: PdfAnnotationSubtype.STAMP,
|
||||
},
|
||||
behavior: {
|
||||
deactivateToolAfterCreate: true,
|
||||
selectAfterCreate: true,
|
||||
},
|
||||
});
|
||||
|
||||
ensureTool({
|
||||
id: 'signatureStamp',
|
||||
name: 'Digital Signature',
|
||||
interaction: { exclusive: false, cursor: 'copy' },
|
||||
@@ -262,7 +570,7 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, showBakedA
|
||||
},
|
||||
});
|
||||
|
||||
annotationApi.addTool({
|
||||
ensureTool({
|
||||
id: 'signatureInk',
|
||||
name: 'Signature Draw',
|
||||
interaction: { exclusive: true, cursor: 'crosshair' },
|
||||
@@ -310,6 +618,7 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, showBakedA
|
||||
<ThumbnailAPIBridge />
|
||||
<RotateAPIBridge />
|
||||
{enableAnnotations && <SignatureAPIBridge ref={signatureApiRef} />}
|
||||
{enableAnnotations && <AnnotationAPIBridge ref={annotationApiRef} />}
|
||||
{enableAnnotations && <HistoryAPIBridge ref={historyApiRef} />}
|
||||
<ExportAPIBridge />
|
||||
<BookmarkAPIBridge />
|
||||
|
||||
Reference in New Issue
Block a user