pdfcedar 0.1.0-beta.0 → 0.1.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +238 -223
- package/bin/pdfcedar-assets.mjs +0 -0
- package/dist/chunks/{errors-Bd8CCmBG.js → errors-Cq5TPos_.js} +3 -3
- package/dist/chunks/pdf-Bt7uz0Yc.js +18800 -0
- package/dist/chunks/{src-xAKLPCPU.js → src-CyL6Tva1.js} +2 -2
- package/dist/index.d.cts +4 -0
- package/dist/index.js +978 -19693
- package/dist/index.umd.cjs +120 -85
- package/dist/pdfcedar.umd.js +1026 -0
- package/dist/types/core/annotation-geometry.d.cts +36 -0
- package/dist/types/core/annotation-manager.d.cts +97 -0
- package/dist/types/core/annotations.d.cts +106 -0
- package/dist/types/core/errors.d.cts +11 -0
- package/dist/types/core/errors.d.ts +5 -2
- package/dist/types/core/events.d.cts +10 -0
- package/dist/types/core/forms.d.cts +109 -0
- package/dist/types/core/index.d.cts +9 -0
- package/dist/types/core/types.d.cts +103 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/core/undo.d.cts +47 -0
- package/dist/types/core/validate.d.cts +22 -0
- package/dist/viewer.d.cts +96 -0
- package/dist/viewer.d.ts +1 -1
- package/package.json +21 -17
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Annotation, AnnotationPatch, Point, Quad } from './annotations.cjs';
|
|
2
|
+
import type { Rect } from './types.cjs';
|
|
3
|
+
export declare function rectFromPoints(a: Point, b: Point): Rect;
|
|
4
|
+
/** The patch that moves `a` by (dx, dy). */
|
|
5
|
+
export declare function translateAnnotation(a: Annotation, dx: number, dy: number): AnnotationPatch;
|
|
6
|
+
/** Whether the UI offers resize handles. Notes are fixed-size icons; markup follows its text. */
|
|
7
|
+
export declare function isResizable(a: Annotation): boolean;
|
|
8
|
+
/** Signatures scale from their corners only, keeping their proportions (a stretched signature looks forged). */
|
|
9
|
+
export declare function resizeHandles(a: Annotation): Handle[];
|
|
10
|
+
/**
|
|
11
|
+
* `resized` (from dragHandle on a corner) scaled back to `original`'s proportions: both sides grow or shrink by
|
|
12
|
+
* the larger of the two changes, anchored at the corner opposite `handle`. Works in any space with y up.
|
|
13
|
+
*/
|
|
14
|
+
export declare function keepAspect(original: Rect, resized: Rect, handle: Handle): Rect;
|
|
15
|
+
export declare function isMovable(a: Annotation): boolean;
|
|
16
|
+
/** The patch that fits `a` into `rect` (shapes take it as-is; ink paths are scaled into it). */
|
|
17
|
+
export declare function resizeAnnotation(a: Annotation, rect: Rect): AnnotationPatch;
|
|
18
|
+
export type Handle = 'nw' | 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w';
|
|
19
|
+
/**
|
|
20
|
+
* The rect after dragging `handle` by (dx, dy) in PDF space (y up). Never flips inside out and never
|
|
21
|
+
* shrinks below `min` points.
|
|
22
|
+
*/
|
|
23
|
+
export declare function dragHandle(rect: Rect, handle: Handle, dx: number, dy: number, min?: number): Rect;
|
|
24
|
+
/** A rect as a QuadPoints quad: top-left, top-right, bottom-left, bottom-right. */
|
|
25
|
+
export declare function quadFromRect(r: Rect): Quad;
|
|
26
|
+
/**
|
|
27
|
+
* Merges per-word/per-span rects into one rect per line, so a highlight is one smooth band per line
|
|
28
|
+
* instead of a row of overlapping boxes. Two rects are on the same line when they overlap vertically
|
|
29
|
+
* by at least half the smaller height and the horizontal gap is under one line height.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergeLineRects(rects: Rect[]): Rect[];
|
|
32
|
+
/**
|
|
33
|
+
* The two wing tips of an open arrowhead at `end`. Shared by the on-screen renderer and the PDF writer so
|
|
34
|
+
* an arrow looks the same everywhere; its reach (3 × stroke width) matches the bounds padding in validate.ts.
|
|
35
|
+
*/
|
|
36
|
+
export declare function arrowHeadPoints(start: Point, end: Point, strokeWidth: number): [Point, Point];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Annotation, AnnotationInput, AnnotationPatch, AnnotationType } from './annotations.cjs';
|
|
2
|
+
import type { User } from './types.cjs';
|
|
3
|
+
import type { UndoManager } from './undo.cjs';
|
|
4
|
+
/**
|
|
5
|
+
* Who caused a change. `document`: loaded from the PDF file itself. `remote` is reserved for
|
|
6
|
+
* collaboration (Milestone 13).
|
|
7
|
+
*/
|
|
8
|
+
export type ChangeSource = 'api' | 'user' | 'undo' | 'redo' | 'remote' | 'document';
|
|
9
|
+
export type AnnotationEvents = {
|
|
10
|
+
annotationAdded: {
|
|
11
|
+
annotation: Annotation;
|
|
12
|
+
source: ChangeSource;
|
|
13
|
+
};
|
|
14
|
+
annotationChanged: {
|
|
15
|
+
annotation: Annotation;
|
|
16
|
+
previous: Annotation;
|
|
17
|
+
source: ChangeSource;
|
|
18
|
+
};
|
|
19
|
+
annotationRemoved: {
|
|
20
|
+
annotation: Annotation;
|
|
21
|
+
source: ChangeSource;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export interface AnnotationManagerOptions {
|
|
25
|
+
undo: UndoManager;
|
|
26
|
+
emit<K extends keyof AnnotationEvents>(event: K, payload: AnnotationEvents[K]): void;
|
|
27
|
+
user?: () => User | undefined;
|
|
28
|
+
pageCount?: () => number;
|
|
29
|
+
now?: () => string;
|
|
30
|
+
newId?: () => string;
|
|
31
|
+
}
|
|
32
|
+
export interface ListFilter {
|
|
33
|
+
page?: number;
|
|
34
|
+
type?: AnnotationType;
|
|
35
|
+
}
|
|
36
|
+
export interface ImportOptions {
|
|
37
|
+
/** Remove every existing annotation first. Default false: imported ids replace matching ones, others are added. */
|
|
38
|
+
replace?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The single source of truth for annotations. Every change is validated, recorded for undo and announced
|
|
42
|
+
* through `emit`. Callers always get copies, so nothing outside can mutate the store.
|
|
43
|
+
*/
|
|
44
|
+
export declare class AnnotationManager {
|
|
45
|
+
private readonly options;
|
|
46
|
+
/** Insertion order is z-order (later = on top), and undo restores removed annotations to their slot. */
|
|
47
|
+
private items;
|
|
48
|
+
private readonly byId;
|
|
49
|
+
constructor(options: AnnotationManagerOptions);
|
|
50
|
+
get(id: string): Annotation | undefined;
|
|
51
|
+
list(filter?: ListFilter): Annotation[];
|
|
52
|
+
/** Replies to `id`, oldest first. */
|
|
53
|
+
replies(id: string): Annotation[];
|
|
54
|
+
add(input: AnnotationInput, source?: ChangeSource): Annotation;
|
|
55
|
+
update(id: string, patch: AnnotationPatch, source?: ChangeSource): Annotation;
|
|
56
|
+
/** Removes the annotation and its whole reply thread as one undo step. */
|
|
57
|
+
/** `withPage`: the annotation's page is being deleted, which also takes applied redactions. */
|
|
58
|
+
remove(id: string, source?: ChangeSource, { withPage }?: {
|
|
59
|
+
withPage?: boolean;
|
|
60
|
+
}): void;
|
|
61
|
+
/**
|
|
62
|
+
* Marks redactions as applied (`redaction.apply()`). Not an undoable edit: applying is final, and the
|
|
63
|
+
* caller clears the undo history so earlier steps can't bring the marks or what's under them back.
|
|
64
|
+
*/
|
|
65
|
+
markApplied(ids: readonly string[], source?: ChangeSource): void;
|
|
66
|
+
/**
|
|
67
|
+
* Applies changes made by other people (collaboration). Not undoable locally, events carry `source: 'remote'`,
|
|
68
|
+
* and the rules for local edits (applied redactions are final…) don't block them: the shared state is the
|
|
69
|
+
* authority. Remote data is validated; entries that aren't valid annotations are skipped and returned.
|
|
70
|
+
*/
|
|
71
|
+
applyRemote(changes: {
|
|
72
|
+
upsert?: readonly unknown[];
|
|
73
|
+
remove?: readonly string[];
|
|
74
|
+
}): {
|
|
75
|
+
rejected: unknown[];
|
|
76
|
+
};
|
|
77
|
+
export(): Annotation[];
|
|
78
|
+
/**
|
|
79
|
+
* Validates everything first, so a bad entry changes nothing; then applies the whole import as one undo step.
|
|
80
|
+
* Ids, authors and timestamps from the JSON are kept.
|
|
81
|
+
*/
|
|
82
|
+
import(json: unknown, options?: ImportOptions, source?: ChangeSource): Annotation[];
|
|
83
|
+
private prepare;
|
|
84
|
+
private requireParent;
|
|
85
|
+
private require;
|
|
86
|
+
private insert;
|
|
87
|
+
private detach;
|
|
88
|
+
private replace;
|
|
89
|
+
/** During undo/redo, events report that instead of the original source. */
|
|
90
|
+
private sourceOf;
|
|
91
|
+
/**
|
|
92
|
+
* Whole seconds: PDF dates can't store milliseconds, so this keeps timestamps identical after a
|
|
93
|
+
* save → reload round trip (change detection by modifiedAt stays reliable).
|
|
94
|
+
*/
|
|
95
|
+
private now;
|
|
96
|
+
private context;
|
|
97
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Rect } from './types.cjs';
|
|
2
|
+
export interface Point {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* One quadrilateral of marked-up text, as in a PDF /QuadPoints entry:
|
|
8
|
+
* [x1, y1, x2, y2, x3, y3, x4, y4] = top-left, top-right, bottom-left, bottom-right (Acrobat's order).
|
|
9
|
+
*/
|
|
10
|
+
export type Quad = [number, number, number, number, number, number, number, number];
|
|
11
|
+
interface AnnotationBase {
|
|
12
|
+
id: string;
|
|
13
|
+
/** 1-based page number. */
|
|
14
|
+
page: number;
|
|
15
|
+
/** Bounding box. Derived automatically for markup, ink, line and arrow annotations. */
|
|
16
|
+
rect: Rect;
|
|
17
|
+
/** `#rrggbb`. Stroke/markup color; the text color for freeText. */
|
|
18
|
+
color: string;
|
|
19
|
+
/** 0..1 */
|
|
20
|
+
opacity: number;
|
|
21
|
+
/** Comment text shown in the note popup / comment thread. */
|
|
22
|
+
contents: string;
|
|
23
|
+
author: string;
|
|
24
|
+
authorId: string;
|
|
25
|
+
/** ISO 8601 */
|
|
26
|
+
createdAt: string;
|
|
27
|
+
/** ISO 8601 */
|
|
28
|
+
modifiedAt: string;
|
|
29
|
+
/** Locked annotations can't be moved, resized or deleted from the UI (the API still can). */
|
|
30
|
+
locked: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface TextMarkupAnnotation extends AnnotationBase {
|
|
33
|
+
type: 'highlight' | 'underline' | 'strikeout';
|
|
34
|
+
quads: Quad[];
|
|
35
|
+
}
|
|
36
|
+
export interface NoteAnnotation extends AnnotationBase {
|
|
37
|
+
type: 'note';
|
|
38
|
+
}
|
|
39
|
+
/** A reply in a comment thread. Maps to a PDF annotation with /IRT pointing at the parent. */
|
|
40
|
+
export interface ReplyAnnotation extends AnnotationBase {
|
|
41
|
+
type: 'reply';
|
|
42
|
+
inReplyTo: string;
|
|
43
|
+
}
|
|
44
|
+
export interface InkAnnotation extends AnnotationBase {
|
|
45
|
+
type: 'ink';
|
|
46
|
+
paths: Point[][];
|
|
47
|
+
strokeWidth: number;
|
|
48
|
+
}
|
|
49
|
+
export interface ShapeAnnotation extends AnnotationBase {
|
|
50
|
+
type: 'rectangle' | 'ellipse';
|
|
51
|
+
strokeWidth: number;
|
|
52
|
+
/** `#rrggbb`, or null for no fill. */
|
|
53
|
+
fillColor: string | null;
|
|
54
|
+
}
|
|
55
|
+
export interface LineAnnotation extends AnnotationBase {
|
|
56
|
+
type: 'line' | 'arrow';
|
|
57
|
+
start: Point;
|
|
58
|
+
end: Point;
|
|
59
|
+
strokeWidth: number;
|
|
60
|
+
}
|
|
61
|
+
export interface FreeTextAnnotation extends AnnotationBase {
|
|
62
|
+
type: 'freeText';
|
|
63
|
+
/** The text itself lives in `contents`, as in PDF FreeText annotations. */
|
|
64
|
+
fontSize: number;
|
|
65
|
+
backgroundColor: string | null;
|
|
66
|
+
borderColor: string | null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A signature image placed on the page. Saved by drawing it into the page content (flattened), so in the saved
|
|
70
|
+
* file it is part of the page, not an annotation.
|
|
71
|
+
*/
|
|
72
|
+
export interface SignatureAnnotation extends AnnotationBase {
|
|
73
|
+
type: 'signature';
|
|
74
|
+
/** A PNG or JPEG data URL (`signatures.add` converts other formats). */
|
|
75
|
+
image: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* An area marked for redaction. Until applied it's an ordinary editable mark (saved as a /Redact annotation that
|
|
79
|
+
* Acrobat can also apply). `redaction.apply()` sets `applied`: the area turns black and, on save, everything under
|
|
80
|
+
* it is removed from the page. Applied redactions can't be changed or removed.
|
|
81
|
+
*/
|
|
82
|
+
export interface RedactionAnnotation extends AnnotationBase {
|
|
83
|
+
type: 'redaction';
|
|
84
|
+
applied: boolean;
|
|
85
|
+
}
|
|
86
|
+
export type Annotation = TextMarkupAnnotation | NoteAnnotation | ReplyAnnotation | InkAnnotation | ShapeAnnotation | LineAnnotation | FreeTextAnnotation | SignatureAnnotation | RedactionAnnotation;
|
|
87
|
+
/** The serializable form; identical to `Annotation` (kept as a name because the public API uses it). */
|
|
88
|
+
export type AnnotationJSON = Annotation;
|
|
89
|
+
export type AnnotationType = Annotation['type'];
|
|
90
|
+
type Defaulted = 'id' | 'rect' | 'color' | 'opacity' | 'contents' | 'author' | 'authorId' | 'createdAt' | 'modifiedAt' | 'locked';
|
|
91
|
+
type Optionalize<T> = T extends Annotation ? Omit<T, Defaulted | OptionalFields<T>> & Partial<Pick<T, Extract<keyof T, Defaulted | OptionalFields<T>>>> : never;
|
|
92
|
+
type OptionalFields<T> = T extends ReplyAnnotation ? 'page' : T extends ShapeAnnotation ? 'strokeWidth' | 'fillColor' : T extends InkAnnotation | LineAnnotation ? 'strokeWidth' : T extends FreeTextAnnotation ? 'fontSize' | 'backgroundColor' | 'borderColor' : T extends RedactionAnnotation ? 'applied' : never;
|
|
93
|
+
/** What `annotations.add()` accepts: the annotation with every defaulted field optional. */
|
|
94
|
+
export type AnnotationInput = Optionalize<Annotation>;
|
|
95
|
+
/** What `annotations.update()` accepts: any fields of the annotation's own type. `id` and `type` can't change. */
|
|
96
|
+
export type AnnotationPatch = Annotation extends infer T ? T extends Annotation ? Partial<Omit<T, 'id' | 'type'>> & {
|
|
97
|
+
id?: string;
|
|
98
|
+
type?: T['type'];
|
|
99
|
+
} : never : never;
|
|
100
|
+
export declare const ANNOTATION_TYPES: readonly AnnotationType[];
|
|
101
|
+
export declare const DEFAULT_COLORS: Record<AnnotationType, string>;
|
|
102
|
+
export declare const DEFAULT_STROKE_WIDTH = 2;
|
|
103
|
+
export declare const DEFAULT_FONT_SIZE = 14;
|
|
104
|
+
/** PDF annotation subtypes PDFCedar reads, edits and writes. Others in a file are left untouched. */
|
|
105
|
+
export declare const PDF_ANNOTATION_SUBTYPES: ReadonlySet<string>;
|
|
106
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Thrown by API methods whose feature belongs to a later milestone. */
|
|
2
|
+
export declare class NotImplementedError extends Error {
|
|
3
|
+
constructor(feature: string, milestone: number);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* A password-protected PDF: opened without the right password, or saved (`save()`/`download()` can't write
|
|
7
|
+
* encrypted files yet). Lives here (not in the writer) so the public entry can export it without loading pdf-lib.
|
|
8
|
+
*/
|
|
9
|
+
export declare class EncryptedDocumentError extends Error {
|
|
10
|
+
constructor(message?: string);
|
|
11
|
+
}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
export declare class NotImplementedError extends Error {
|
|
3
3
|
constructor(feature: string, milestone: number);
|
|
4
4
|
}
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* A password-protected PDF: opened without the right password, or saved (`save()`/`download()` can't write
|
|
7
|
+
* encrypted files yet). Lives here (not in the writer) so the public entry can export it without loading pdf-lib.
|
|
8
|
+
*/
|
|
6
9
|
export declare class EncryptedDocumentError extends Error {
|
|
7
|
-
constructor();
|
|
10
|
+
constructor(message?: string);
|
|
8
11
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type EventMap = Record<string, unknown>;
|
|
2
|
+
export type Handler<T> = (payload: T) => void;
|
|
3
|
+
/** Small typed event emitter. Handler errors are isolated so one bad listener can't break the viewer. */
|
|
4
|
+
export declare class Emitter<Events extends EventMap> {
|
|
5
|
+
private readonly handlers;
|
|
6
|
+
on<K extends keyof Events>(event: K, handler: Handler<Events[K]>): void;
|
|
7
|
+
off<K extends keyof Events>(event: K, handler: Handler<Events[K]>): void;
|
|
8
|
+
emit<K extends keyof Events>(event: K, payload: Events[K]): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ChangeSource } from './annotation-manager.cjs';
|
|
2
|
+
import type { FormValues, Rect } from './types.cjs';
|
|
3
|
+
import type { UndoManager } from './undo.cjs';
|
|
4
|
+
export type FormFieldType = 'text' | 'checkbox' | 'radio' | 'dropdown' | 'listbox';
|
|
5
|
+
export type FormValue = FormValues[string];
|
|
6
|
+
export interface FormOption {
|
|
7
|
+
/** What is stored in the PDF and returned by getValues (the export value). */
|
|
8
|
+
value: string;
|
|
9
|
+
/** What the user sees. */
|
|
10
|
+
label: string;
|
|
11
|
+
}
|
|
12
|
+
/** One place a field appears. A radio group has one widget per button; a text field can repeat across pages. */
|
|
13
|
+
export interface FormWidget {
|
|
14
|
+
/** pdf.js annotation id ("12R"): the widget's object number, used to find it again when saving. */
|
|
15
|
+
id: string;
|
|
16
|
+
/** 0-based page in the original file. */
|
|
17
|
+
pageIndex: number;
|
|
18
|
+
rect: Rect;
|
|
19
|
+
/** Checkbox / radio: the value this widget stands for when it is on. */
|
|
20
|
+
exportValue?: string;
|
|
21
|
+
/** Points; 0 means "auto" (fit the box). */
|
|
22
|
+
fontSize: number;
|
|
23
|
+
/** `#rrggbb` */
|
|
24
|
+
color: string;
|
|
25
|
+
align: 'left' | 'center' | 'right';
|
|
26
|
+
background: string | null;
|
|
27
|
+
border: string | null;
|
|
28
|
+
/** Hidden widgets keep their field's value but aren't drawn. */
|
|
29
|
+
hidden: boolean;
|
|
30
|
+
/** The widget's own rotation (/MK /R), on top of the page's. */
|
|
31
|
+
rotation: 0 | 90 | 180 | 270;
|
|
32
|
+
}
|
|
33
|
+
export interface FormField {
|
|
34
|
+
/** Fully qualified name ("address.city"); the key in getValues/setValues. */
|
|
35
|
+
name: string;
|
|
36
|
+
type: FormFieldType;
|
|
37
|
+
readOnly: boolean;
|
|
38
|
+
required: boolean;
|
|
39
|
+
multiline?: boolean;
|
|
40
|
+
password?: boolean;
|
|
41
|
+
/** Text: maximum characters (0 = none). */
|
|
42
|
+
maxLength?: number;
|
|
43
|
+
/** Text: one character per cell. */
|
|
44
|
+
comb?: boolean;
|
|
45
|
+
/** Dropdown / listbox. */
|
|
46
|
+
options?: FormOption[];
|
|
47
|
+
/** Listbox: several values. */
|
|
48
|
+
multiSelect?: boolean;
|
|
49
|
+
/** Dropdown: also accepts typed text that isn't an option. */
|
|
50
|
+
editable?: boolean;
|
|
51
|
+
widgets: FormWidget[];
|
|
52
|
+
/** The value in the file as loaded. */
|
|
53
|
+
value: FormValue;
|
|
54
|
+
}
|
|
55
|
+
/** Thrown by `forms.setValues` for an unknown field or a value the field can't hold. Nothing is changed. */
|
|
56
|
+
export declare class FormValueError extends TypeError {
|
|
57
|
+
readonly field: string;
|
|
58
|
+
constructor(field: string, message: string);
|
|
59
|
+
}
|
|
60
|
+
export interface FormManagerOptions {
|
|
61
|
+
undo: UndoManager;
|
|
62
|
+
emit(payload: {
|
|
63
|
+
name: string;
|
|
64
|
+
value: FormValue;
|
|
65
|
+
source: ChangeSource;
|
|
66
|
+
}): void;
|
|
67
|
+
/** False for fields that are gone from the document (every page they appear on was deleted). */
|
|
68
|
+
available?: (field: FormField) => boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Form field values with undo and change events. The field structure comes from the PDF and never changes;
|
|
72
|
+
* only values (and whether the form has been flattened) do.
|
|
73
|
+
*/
|
|
74
|
+
export declare class FormManager {
|
|
75
|
+
private readonly o;
|
|
76
|
+
private readonly byName;
|
|
77
|
+
private readonly current;
|
|
78
|
+
private flattenedState;
|
|
79
|
+
private readonly listeners;
|
|
80
|
+
constructor(o: FormManagerOptions);
|
|
81
|
+
/** Sets the fields read from the file. Not an edit: no undo step, no events. */
|
|
82
|
+
load(fields: readonly FormField[]): void;
|
|
83
|
+
/** Fields currently in the document. */
|
|
84
|
+
get fields(): readonly FormField[];
|
|
85
|
+
field(name: string): FormField | undefined;
|
|
86
|
+
private isAvailable;
|
|
87
|
+
get flattened(): boolean;
|
|
88
|
+
value(name: string): FormValue | undefined;
|
|
89
|
+
/** Every field's value; empty once the form is flattened (the fields no longer exist). */
|
|
90
|
+
values(): FormValues;
|
|
91
|
+
/** Fields whose value differs from the file's, for saving. */
|
|
92
|
+
changed(): FormValues;
|
|
93
|
+
/** Validates every entry first, then applies them as one undo step. */
|
|
94
|
+
setValues(values: FormValues, source?: ChangeSource): void;
|
|
95
|
+
/**
|
|
96
|
+
* Values set by other people (collaboration): validated like setValues, applied without undo, events with
|
|
97
|
+
* `source: 'remote'`. Unknown fields and invalid values are skipped (the sender may have another file).
|
|
98
|
+
*/
|
|
99
|
+
applyRemote(values: FormValues): void;
|
|
100
|
+
/** Marks the form for flattening: on save the fields become part of the page. Undoable. */
|
|
101
|
+
flatten(): void;
|
|
102
|
+
/** Called with the names whose value changed (all names for load/flatten). */
|
|
103
|
+
onChange(listener: (names: readonly string[]) => void): () => void;
|
|
104
|
+
private setFlattened;
|
|
105
|
+
private apply;
|
|
106
|
+
private notify;
|
|
107
|
+
}
|
|
108
|
+
/** The canonical value for `field`, or a FormValueError explaining why `raw` doesn't fit. */
|
|
109
|
+
export declare function normalizeValue(field: FormField, raw: unknown): FormValue;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Emitter, type EventMap, type Handler } from './events.cjs';
|
|
2
|
+
export type * from './types.cjs';
|
|
3
|
+
export * from './annotations.cjs';
|
|
4
|
+
export { AnnotationManager, type AnnotationEvents, type AnnotationManagerOptions, type ChangeSource, type ImportOptions, type ListFilter, } from './annotation-manager.cjs';
|
|
5
|
+
export * from './annotation-geometry.cjs';
|
|
6
|
+
export { UndoManager, type Command, type UndoState } from './undo.cjs';
|
|
7
|
+
export { AnnotationValidationError, newId, normalizeAnnotation, normalizeColor, type NormalizeContext } from './validate.cjs';
|
|
8
|
+
export { NotImplementedError, EncryptedDocumentError } from './errors.cjs';
|
|
9
|
+
export { FormManager, FormValueError, normalizeValue, type FormField, type FormFieldType, type FormOption, type FormValue, type FormWidget, type FormManagerOptions } from './forms.cjs';
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { AnnotationEvents, ChangeSource } from './annotation-manager.cjs';
|
|
2
|
+
import type { AnnotationJSON } from './annotations.cjs';
|
|
3
|
+
export type DocumentSource = string | File | Blob | ArrayBuffer;
|
|
4
|
+
export type ToolName = 'pan' | 'select' | 'zoom' | 'search' | 'highlight' | 'underline' | 'strikeout' | 'note' | 'ink' | 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'freeText' | 'signature' | 'redaction' | 'pages' | 'download' | 'print';
|
|
5
|
+
export interface ThemeObject {
|
|
6
|
+
/** CSS custom properties applied to the viewer root, e.g. `{ '--pl-accent': '#2563eb' }`. */
|
|
7
|
+
[cssVariable: `--${string}`]: string;
|
|
8
|
+
}
|
|
9
|
+
export interface User {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CollaborationOptions {
|
|
14
|
+
serverUrl: string;
|
|
15
|
+
roomId: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ViewerOptions {
|
|
18
|
+
container: HTMLElement;
|
|
19
|
+
document: DocumentSource;
|
|
20
|
+
/**
|
|
21
|
+
* Your PDFCedar licence key (`PL1.…`). Checked offline against the page's domain; without a valid key the
|
|
22
|
+
* viewer runs in trial mode, with a watermark on the pages. Any valid key also works on localhost.
|
|
23
|
+
*/
|
|
24
|
+
licenseKey?: string;
|
|
25
|
+
theme?: 'light' | 'dark' | ThemeObject;
|
|
26
|
+
toolbar?: ToolName[];
|
|
27
|
+
readOnly?: boolean;
|
|
28
|
+
user?: User;
|
|
29
|
+
collaboration?: CollaborationOptions;
|
|
30
|
+
/**
|
|
31
|
+
* URL of the folder holding PDFCedar's PDF engine files (a copy of `pdfcedar/dist/pdfjs/`).
|
|
32
|
+
* Only needed when your bundler doesn't serve them next to the PDFCedar bundle; by default they're
|
|
33
|
+
* found automatically. Applies to every viewer on the page.
|
|
34
|
+
*/
|
|
35
|
+
assetBaseUrl?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Where the user's saved signatures persist. Without it they're kept in memory for this page session
|
|
38
|
+
* (per user id); PDFCedar itself never writes them to browser storage.
|
|
39
|
+
*/
|
|
40
|
+
signatureStore?: SignatureStore;
|
|
41
|
+
/**
|
|
42
|
+
* Password of a password-protected PDF. If it's missing or wrong, the viewer asks the user for it;
|
|
43
|
+
* `createViewer` rejects with `EncryptedDocumentError` if they cancel.
|
|
44
|
+
*/
|
|
45
|
+
password?: string;
|
|
46
|
+
/** Headers sent when `document` is a URL, e.g. `{ Authorization: 'Bearer …' }` for files behind a login. */
|
|
47
|
+
httpHeaders?: Record<string, string>;
|
|
48
|
+
/** Send cookies when `document` is a URL on another origin (the server must allow credentials). */
|
|
49
|
+
withCredentials?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/** A signature the user chose to reuse. */
|
|
52
|
+
export interface SavedSignature {
|
|
53
|
+
id: string;
|
|
54
|
+
/** PNG or JPEG data URL. */
|
|
55
|
+
image: string;
|
|
56
|
+
/** ISO 8601 */
|
|
57
|
+
createdAt: string;
|
|
58
|
+
}
|
|
59
|
+
/** Persistence for saved signatures, provided by the app (e.g. its backend, per signed-in user). */
|
|
60
|
+
export interface SignatureStore {
|
|
61
|
+
/** Called once, the first time the user opens the signature dialog. */
|
|
62
|
+
load(): SavedSignature[] | Promise<SavedSignature[]>;
|
|
63
|
+
/** Called with the full list after every change (a signature saved or removed). */
|
|
64
|
+
save(signatures: SavedSignature[]): void | Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/** A rectangle in PDF user space (points, origin bottom-left). */
|
|
67
|
+
export interface Rect {
|
|
68
|
+
x: number;
|
|
69
|
+
y: number;
|
|
70
|
+
width: number;
|
|
71
|
+
height: number;
|
|
72
|
+
}
|
|
73
|
+
export interface SearchResult {
|
|
74
|
+
page: number;
|
|
75
|
+
/** Index of the match within the page's text. */
|
|
76
|
+
index: number;
|
|
77
|
+
text: string;
|
|
78
|
+
rects: Rect[];
|
|
79
|
+
}
|
|
80
|
+
export type FitMode = 'width' | 'page';
|
|
81
|
+
export type Rotation = 90 | 180 | 270;
|
|
82
|
+
export type FormValues = Record<string, string | boolean | string[]>;
|
|
83
|
+
export type ViewerEvents = AnnotationEvents & {
|
|
84
|
+
documentLoaded: {
|
|
85
|
+
pageCount: number;
|
|
86
|
+
};
|
|
87
|
+
pageChanged: {
|
|
88
|
+
page: number;
|
|
89
|
+
previousPage: number;
|
|
90
|
+
};
|
|
91
|
+
formFieldChanged: {
|
|
92
|
+
name: string;
|
|
93
|
+
value: FormValues[string];
|
|
94
|
+
source: ChangeSource;
|
|
95
|
+
};
|
|
96
|
+
signatureAdded: {
|
|
97
|
+
annotation: AnnotationJSON;
|
|
98
|
+
};
|
|
99
|
+
saved: {
|
|
100
|
+
bytes: Uint8Array;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
export type ViewerEventName = keyof ViewerEvents;
|
|
@@ -38,6 +38,15 @@ export interface ViewerOptions {
|
|
|
38
38
|
* (per user id); PDFCedar itself never writes them to browser storage.
|
|
39
39
|
*/
|
|
40
40
|
signatureStore?: SignatureStore;
|
|
41
|
+
/**
|
|
42
|
+
* Password of a password-protected PDF. If it's missing or wrong, the viewer asks the user for it;
|
|
43
|
+
* `createViewer` rejects with `EncryptedDocumentError` if they cancel.
|
|
44
|
+
*/
|
|
45
|
+
password?: string;
|
|
46
|
+
/** Headers sent when `document` is a URL, e.g. `{ Authorization: 'Bearer …' }` for files behind a login. */
|
|
47
|
+
httpHeaders?: Record<string, string>;
|
|
48
|
+
/** Send cookies when `document` is a URL on another origin (the server must allow credentials). */
|
|
49
|
+
withCredentials?: boolean;
|
|
41
50
|
}
|
|
42
51
|
/** A signature the user chose to reuse. */
|
|
43
52
|
export interface SavedSignature {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** A change that has already been applied and knows how to revert and re-apply itself. */
|
|
2
|
+
export interface Command {
|
|
3
|
+
/** Shown in UIs, e.g. "Add highlight". */
|
|
4
|
+
label: string;
|
|
5
|
+
undo(): void;
|
|
6
|
+
redo(): void;
|
|
7
|
+
}
|
|
8
|
+
export interface UndoState {
|
|
9
|
+
canUndo: boolean;
|
|
10
|
+
canRedo: boolean;
|
|
11
|
+
undoLabel: string | null;
|
|
12
|
+
redoLabel: string | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Linear undo history shared by every kind of edit (annotations, pages, forms, signatures).
|
|
16
|
+
* Edits record a Command after applying themselves; `transaction` folds several into one step.
|
|
17
|
+
*/
|
|
18
|
+
export declare class UndoManager {
|
|
19
|
+
private readonly limit;
|
|
20
|
+
private readonly undoStack;
|
|
21
|
+
private redoStack;
|
|
22
|
+
/** Commands collected by the open transaction(s); null when none is open. */
|
|
23
|
+
private pending;
|
|
24
|
+
private depth;
|
|
25
|
+
/** Set while undoing/redoing, so the edits a replay triggers aren't recorded again. */
|
|
26
|
+
private replaying;
|
|
27
|
+
private untrackedDepth;
|
|
28
|
+
private readonly listeners;
|
|
29
|
+
constructor(limit?: number);
|
|
30
|
+
/** Which replay is running, if any. Lets edits report `source: 'undo' | 'redo'` in their events. */
|
|
31
|
+
get replayKind(): 'undo' | 'redo' | null;
|
|
32
|
+
get state(): UndoState;
|
|
33
|
+
record(command: Command): void;
|
|
34
|
+
/**
|
|
35
|
+
* Runs `fn`, recording everything it does as a single undo step. If `fn` throws, the changes it already
|
|
36
|
+
* made are rolled back and the error is rethrown, so a failed batch never leaves half an edit behind.
|
|
37
|
+
*/
|
|
38
|
+
transaction<T>(label: string, fn: () => T): T;
|
|
39
|
+
/** Runs `fn` without recording anything, e.g. when loading a document's own annotations. */
|
|
40
|
+
untracked<T>(fn: () => T): T;
|
|
41
|
+
undo(): boolean;
|
|
42
|
+
redo(): boolean;
|
|
43
|
+
clear(): void;
|
|
44
|
+
onChange(listener: (state: UndoState) => void): () => void;
|
|
45
|
+
private replay;
|
|
46
|
+
private notify;
|
|
47
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Annotation } from './annotations.cjs';
|
|
2
|
+
import type { User } from './types.cjs';
|
|
3
|
+
export declare class AnnotationValidationError extends TypeError {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
constructor(path: string, message: string);
|
|
6
|
+
}
|
|
7
|
+
export interface NormalizeContext {
|
|
8
|
+
now(): string;
|
|
9
|
+
newId(): string;
|
|
10
|
+
user?: User | undefined;
|
|
11
|
+
/** When known, pages outside 1..pageCount are rejected. */
|
|
12
|
+
pageCount?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** Accepts #rgb or #rrggbb in any case; always returns lowercase #rrggbb. */
|
|
15
|
+
export declare function normalizeColor(path: string, v: unknown): string;
|
|
16
|
+
/**
|
|
17
|
+
* Validates `input` and fills defaults, returning a complete annotation. Throws AnnotationValidationError
|
|
18
|
+
* naming the offending field. `prefix` labels paths, e.g. "annotations[3]" during import.
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeAnnotation(input: unknown, ctx: NormalizeContext, prefix?: string): Annotation;
|
|
21
|
+
/** RFC 4122 v4. crypto.randomUUID only exists in secure contexts, so fall back to getRandomValues. */
|
|
22
|
+
export declare function newId(): string;
|