@embedpdf/plugin-annotation 2.8.0 → 2.9.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.
Files changed (52) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +814 -139
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/geometry/cloudy-border.d.ts +90 -0
  6. package/dist/lib/geometry/index.d.ts +1 -0
  7. package/dist/lib/handlers/types.d.ts +2 -1
  8. package/dist/lib/tools/default-tools.d.ts +38 -87
  9. package/dist/lib/tools/types.d.ts +32 -1
  10. package/dist/preact/index.cjs +1 -1
  11. package/dist/preact/index.cjs.map +1 -1
  12. package/dist/preact/index.js +352 -239
  13. package/dist/preact/index.js.map +1 -1
  14. package/dist/react/index.cjs +1 -1
  15. package/dist/react/index.cjs.map +1 -1
  16. package/dist/react/index.js +352 -239
  17. package/dist/react/index.js.map +1 -1
  18. package/dist/shared/components/annotation-container.d.ts +4 -2
  19. package/dist/shared/components/annotations/circle.d.ts +6 -2
  20. package/dist/shared/components/annotations/polygon.d.ts +3 -1
  21. package/dist/shared/components/annotations/square.d.ts +6 -2
  22. package/dist/shared/components/types.d.ts +6 -2
  23. package/dist/shared-preact/components/annotation-container.d.ts +4 -2
  24. package/dist/shared-preact/components/annotations/circle.d.ts +6 -2
  25. package/dist/shared-preact/components/annotations/polygon.d.ts +3 -1
  26. package/dist/shared-preact/components/annotations/square.d.ts +6 -2
  27. package/dist/shared-preact/components/types.d.ts +6 -2
  28. package/dist/shared-react/components/annotation-container.d.ts +4 -2
  29. package/dist/shared-react/components/annotations/circle.d.ts +6 -2
  30. package/dist/shared-react/components/annotations/polygon.d.ts +3 -1
  31. package/dist/shared-react/components/annotations/square.d.ts +6 -2
  32. package/dist/shared-react/components/types.d.ts +6 -2
  33. package/dist/svelte/components/annotations/Circle.svelte.d.ts +3 -1
  34. package/dist/svelte/components/annotations/Polygon.svelte.d.ts +1 -0
  35. package/dist/svelte/components/annotations/Square.svelte.d.ts +3 -1
  36. package/dist/svelte/components/types.d.ts +2 -1
  37. package/dist/svelte/context/types.d.ts +6 -2
  38. package/dist/svelte/index.cjs +1 -1
  39. package/dist/svelte/index.cjs.map +1 -1
  40. package/dist/svelte/index.js +505 -293
  41. package/dist/svelte/index.js.map +1 -1
  42. package/dist/vue/components/annotation-container.vue.d.ts +7 -6
  43. package/dist/vue/components/annotations/circle.vue.d.ts +5 -1
  44. package/dist/vue/components/annotations/polygon.vue.d.ts +2 -0
  45. package/dist/vue/components/annotations/square.vue.d.ts +5 -1
  46. package/dist/vue/components/annotations.vue.d.ts +8 -9
  47. package/dist/vue/context/types.d.ts +6 -2
  48. package/dist/vue/index.cjs +1 -1
  49. package/dist/vue/index.cjs.map +1 -1
  50. package/dist/vue/index.js +259 -121
  51. package/dist/vue/index.js.map +1 -1
  52. package/package.json +10 -10
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Cloudy border path generator for PDF annotations.
3
+ *
4
+ * Framework-agnostic utility that generates SVG path `d` strings for cloudy
5
+ * (scalloped) borders on Rectangle, Ellipse, and Polygon shapes.
6
+ *
7
+ * Derived from Apache PDFBox's CloudyBorder.java:
8
+ * https://github.com/apache/pdfbox/blob/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/annotation/handlers/CloudyBorder.java
9
+ *
10
+ * Original code licensed under the Apache License, Version 2.0:
11
+ * https://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Substantially modified: ported from Java to TypeScript, adapted for SVG
14
+ * path output, and reworked curl distribution and merging logic.
15
+ *
16
+ * Copyright (c) 2026 CloudPDF / EmbedPDF
17
+ *
18
+ * @module
19
+ */
20
+ interface BBox {
21
+ minX: number;
22
+ minY: number;
23
+ maxX: number;
24
+ maxY: number;
25
+ }
26
+ /** Rect differences (inset from annotation Rect to drawn shape). */
27
+ export interface RectDifferences {
28
+ left: number;
29
+ top: number;
30
+ right: number;
31
+ bottom: number;
32
+ }
33
+ export interface CloudyPathResult {
34
+ /** SVG path `d` attribute string */
35
+ path: string;
36
+ /** Bounding box of the generated cloudy border (in annotation-local coords) */
37
+ bbox: BBox;
38
+ }
39
+ /**
40
+ * Returns the per-side outward extent of a cloudy border (how far the
41
+ * scallop peaks + stroke extend beyond the inner shape boundary).
42
+ *
43
+ * Use this to compute `rectangleDifferences` for Square/Circle or the
44
+ * padding for Polygon Rect computation.
45
+ */
46
+ export declare function getCloudyBorderExtent(intensity: number, lineWidth: number, isEllipse: boolean): number;
47
+ /**
48
+ * Generates a cloudy border SVG path for a rectangle (Square annotation).
49
+ *
50
+ * @param rect - The annotation rect `{ x, y, width, height }` (top-left origin)
51
+ * @param rd - Rectangle differences (inset), or undefined
52
+ * @param intensity - Cloudy border intensity (typically 1 or 2)
53
+ * @param lineWidth - Stroke width of the annotation border
54
+ */
55
+ export declare function generateCloudyRectanglePath(rect: {
56
+ x: number;
57
+ y: number;
58
+ width: number;
59
+ height: number;
60
+ }, rd: RectDifferences | undefined, intensity: number, lineWidth: number): CloudyPathResult;
61
+ /**
62
+ * Generates a cloudy border SVG path for an ellipse (Circle annotation).
63
+ *
64
+ * @param rect - The annotation rect `{ x, y, width, height }` (top-left origin)
65
+ * @param rd - Rectangle differences (inset), or undefined
66
+ * @param intensity - Cloudy border intensity (typically 1 or 2)
67
+ * @param lineWidth - Stroke width of the annotation border
68
+ */
69
+ export declare function generateCloudyEllipsePath(rect: {
70
+ x: number;
71
+ y: number;
72
+ width: number;
73
+ height: number;
74
+ }, rd: RectDifferences | undefined, intensity: number, lineWidth: number): CloudyPathResult;
75
+ /**
76
+ * Generates a cloudy border SVG path for a polygon.
77
+ *
78
+ * @param vertices - The polygon vertices in annotation-local coordinates
79
+ * @param rectOrigin - The annotation rect origin `{ x, y }` for coordinate translation
80
+ * @param intensity - Cloudy border intensity (typically 1 or 2)
81
+ * @param lineWidth - Stroke width of the annotation border
82
+ */
83
+ export declare function generateCloudyPolygonPath(vertices: ReadonlyArray<{
84
+ x: number;
85
+ y: number;
86
+ }>, rectOrigin: {
87
+ x: number;
88
+ y: number;
89
+ }, intensity: number, lineWidth: number): CloudyPathResult;
90
+ export {};
@@ -1 +1,2 @@
1
1
  export * from './rotation';
2
+ export * from './cloudy-border';
@@ -1,5 +1,5 @@
1
1
  import { PointerEventHandlersWithLifecycle } from '@embedpdf/plugin-interaction-manager';
2
- import { PdfAnnotationObject, PdfAnnotationSubtype, Rect, Rotation, Size, AnnotationCreateContext, PdfAnnotationBorderStyle, Position, LineEndings, PdfInkListObject, PdfStandardFont, PdfTextAlignment, PdfVerticalAlignment } from '@embedpdf/models';
2
+ import { PdfAnnotationObject, PdfAnnotationSubtype, Rect, Rotation, Size, AnnotationCreateContext, PdfAnnotationBorderStyle, Position, LineEndings, PdfInkListObject, PdfStandardFont, PdfTextAlignment, PdfVerticalAlignment, PdfBlendMode } from '@embedpdf/models';
3
3
  import { FormattedSelection } from '@embedpdf/plugin-selection';
4
4
  import { AnnotationTool } from '../tools/types';
5
5
  export interface CirclePreviewData {
@@ -54,6 +54,7 @@ export interface InkPreviewData {
54
54
  strokeWidth: number;
55
55
  strokeColor: string;
56
56
  opacity: number;
57
+ blendMode?: PdfBlendMode;
57
58
  }
58
59
  export interface FreeTextPreviewData {
59
60
  rect: Rect;
@@ -1,8 +1,33 @@
1
1
  import { PdfAnnotationBorderStyle, PdfAnnotationLineEnding, PdfAnnotationSubtype, PdfBlendMode, PdfStandardFont, PdfTextAlignment, PdfVerticalAlignment } from '@embedpdf/models';
2
2
  export declare const defaultTools: ({
3
+ id: string;
4
+ name: string;
5
+ matchScore: (annotation: import('@embedpdf/models').PdfAnnotationObject) => number;
6
+ defaults: Partial<import('@embedpdf/models').PdfInkAnnoObject>;
7
+ interaction: {
8
+ mode?: string;
9
+ exclusive: boolean;
10
+ cursor?: string;
11
+ textSelection?: boolean;
12
+ showSelectionRects?: boolean;
13
+ isDraggable?: import('./types').DynamicBooleanProp;
14
+ isResizable?: import('./types').DynamicBooleanProp;
15
+ isRotatable?: import('./types').DynamicBooleanProp;
16
+ lockAspectRatio?: import('./types').DynamicBooleanProp;
17
+ lockGroupAspectRatio?: import('./types').DynamicBooleanProp;
18
+ isGroupDraggable?: import('./types').DynamicBooleanProp;
19
+ isGroupResizable?: import('./types').DynamicBooleanProp;
20
+ isGroupRotatable?: import('./types').DynamicBooleanProp;
21
+ };
22
+ behavior?: ({
23
+ deactivateToolAfterCreate?: boolean;
24
+ selectAfterCreate?: boolean;
25
+ useAppearanceStream?: boolean;
26
+ } & import('./types').InkBehavior) | undefined;
27
+ } | {
3
28
  id: "highlight";
4
29
  name: string;
5
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
30
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
6
31
  interaction: {
7
32
  exclusive: false;
8
33
  textSelection: true;
@@ -39,7 +64,7 @@ export declare const defaultTools: ({
39
64
  } | {
40
65
  id: "underline";
41
66
  name: string;
42
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
67
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
43
68
  interaction: {
44
69
  exclusive: false;
45
70
  textSelection: true;
@@ -76,7 +101,7 @@ export declare const defaultTools: ({
76
101
  } | {
77
102
  id: "strikeout";
78
103
  name: string;
79
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
104
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
80
105
  interaction: {
81
106
  exclusive: false;
82
107
  textSelection: true;
@@ -113,7 +138,7 @@ export declare const defaultTools: ({
113
138
  } | {
114
139
  id: "squiggly";
115
140
  name: string;
116
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
141
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
117
142
  interaction: {
118
143
  exclusive: false;
119
144
  textSelection: true;
@@ -150,7 +175,7 @@ export declare const defaultTools: ({
150
175
  } | {
151
176
  id: "insertText";
152
177
  name: string;
153
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0 | 2;
178
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1 | 2;
154
179
  interaction: {
155
180
  exclusive: false;
156
181
  textSelection: true;
@@ -221,84 +246,10 @@ export declare const defaultTools: ({
221
246
  };
222
247
  clickBehavior?: undefined;
223
248
  behavior?: undefined;
224
- } | {
225
- id: "ink";
226
- name: string;
227
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 5;
228
- interaction: {
229
- exclusive: false;
230
- cursor: string;
231
- isDraggable: true;
232
- isResizable: true;
233
- lockAspectRatio: false;
234
- textSelection?: undefined;
235
- isRotatable?: undefined;
236
- isGroupDraggable?: undefined;
237
- isGroupResizable?: undefined;
238
- showSelectionRects?: undefined;
239
- lockGroupAspectRatio?: undefined;
240
- };
241
- defaults: {
242
- type: PdfAnnotationSubtype.INK;
243
- strokeColor: string;
244
- color: string;
245
- opacity: number;
246
- strokeWidth: number;
247
- blendMode?: undefined;
248
- intent?: undefined;
249
- strokeStyle?: undefined;
250
- lineEndings?: undefined;
251
- contents?: undefined;
252
- fontSize?: undefined;
253
- fontColor?: undefined;
254
- fontFamily?: undefined;
255
- textAlign?: undefined;
256
- verticalAlign?: undefined;
257
- backgroundColor?: undefined;
258
- };
259
- clickBehavior?: undefined;
260
- behavior?: undefined;
261
- } | {
262
- id: "inkHighlighter";
263
- name: string;
264
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 10;
265
- interaction: {
266
- exclusive: false;
267
- cursor: string;
268
- isDraggable: true;
269
- isResizable: true;
270
- lockAspectRatio: false;
271
- lockGroupAspectRatio: (a: import('@embedpdf/models').PdfAnnotationObject) => boolean;
272
- textSelection?: undefined;
273
- isRotatable?: undefined;
274
- isGroupDraggable?: undefined;
275
- isGroupResizable?: undefined;
276
- showSelectionRects?: undefined;
277
- };
278
- defaults: {
279
- type: PdfAnnotationSubtype.INK;
280
- intent: string;
281
- strokeColor: string;
282
- color: string;
283
- opacity: number;
284
- strokeWidth: number;
285
- blendMode: PdfBlendMode.Multiply;
286
- strokeStyle?: undefined;
287
- lineEndings?: undefined;
288
- contents?: undefined;
289
- fontSize?: undefined;
290
- fontColor?: undefined;
291
- fontFamily?: undefined;
292
- textAlign?: undefined;
293
- verticalAlign?: undefined;
294
- backgroundColor?: undefined;
295
- };
296
- clickBehavior?: undefined;
297
- behavior?: undefined;
298
249
  } | {
299
250
  id: "circle";
300
251
  name: string;
301
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
252
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
302
253
  interaction: {
303
254
  exclusive: false;
304
255
  cursor: string;
@@ -344,7 +295,7 @@ export declare const defaultTools: ({
344
295
  } | {
345
296
  id: "square";
346
297
  name: string;
347
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
298
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
348
299
  interaction: {
349
300
  exclusive: false;
350
301
  cursor: string;
@@ -390,7 +341,7 @@ export declare const defaultTools: ({
390
341
  } | {
391
342
  id: "line";
392
343
  name: string;
393
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 5;
344
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 5 | 0;
394
345
  interaction: {
395
346
  exclusive: false;
396
347
  cursor: string;
@@ -479,7 +430,7 @@ export declare const defaultTools: ({
479
430
  } | {
480
431
  id: "polyline";
481
432
  name: string;
482
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
433
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
483
434
  interaction: {
484
435
  exclusive: false;
485
436
  cursor: string;
@@ -516,7 +467,7 @@ export declare const defaultTools: ({
516
467
  } | {
517
468
  id: "polygon";
518
469
  name: string;
519
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
470
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
520
471
  interaction: {
521
472
  exclusive: false;
522
473
  cursor: string;
@@ -553,7 +504,7 @@ export declare const defaultTools: ({
553
504
  } | {
554
505
  id: "textComment";
555
506
  name: string;
556
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
507
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
557
508
  interaction: {
558
509
  exclusive: false;
559
510
  cursor: string;
@@ -594,7 +545,7 @@ export declare const defaultTools: ({
594
545
  } | {
595
546
  id: "freeText";
596
547
  name: string;
597
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
548
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
598
549
  interaction: {
599
550
  exclusive: false;
600
551
  cursor: string;
@@ -644,7 +595,7 @@ export declare const defaultTools: ({
644
595
  } | {
645
596
  id: "stamp";
646
597
  name: string;
647
- matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 1 | 0;
598
+ matchScore: (a: import('@embedpdf/models').PdfAnnotationObject) => 0 | 1;
648
599
  interaction: {
649
600
  exclusive: false;
650
601
  cursor: string;
@@ -83,6 +83,37 @@ type InsertUprightBehaviorFor<T extends PdfAnnotationObject> = Extract<T['type']
83
83
  /** Counter-rotate new annotations to appear visually upright on rotated pages. */
84
84
  insertUpright?: boolean;
85
85
  };
86
+ /**
87
+ * Ink-specific behavior settings. Only available on tools whose annotation
88
+ * type is PdfAnnotationSubtype.INK (i.e. 'ink' and 'inkHighlighter').
89
+ */
90
+ export interface InkBehavior {
91
+ /** ms of pointer inactivity before the accumulated strokes are committed. Default: 800. */
92
+ commitDelay?: number;
93
+ /** When true, line-like strokes are snapped to a clean 2-point straight line on pointerUp. */
94
+ smartLineRecognition?: boolean;
95
+ /**
96
+ * Maximum allowed perpendicular-deviation ratio (maxDeviation / strokeLength) for a stroke
97
+ * to qualify as a straight line. Lower = stricter. Default: 0.15.
98
+ */
99
+ smartLineThreshold?: number;
100
+ /**
101
+ * How many degrees from horizontal or vertical a recognised straight line may deviate
102
+ * before axis-snapping is skipped. Default: 15.
103
+ */
104
+ snapAngleDeg?: number;
105
+ }
106
+ /**
107
+ * Non-distributive conditional: wrapping both sides in [...] prevents TypeScript from
108
+ * distributing over a union. [PdfAnnotationObject] extends [PdfInkAnnoObject] is false
109
+ * (the full union is not a subtype of the specific ink type), so InkBehavior is only added
110
+ * when T is specifically the INK annotation type.
111
+ */
112
+ type InkBehaviorFor<T extends PdfAnnotationObject> = [T] extends [
113
+ Extract<PdfAnnotationObject, {
114
+ type: PdfAnnotationSubtype.INK;
115
+ }>
116
+ ] ? InkBehavior : {};
86
117
  /**
87
118
  * The primary interface for defining an annotation tool.
88
119
  * Uses a type alias to properly combine the base interface with conditional properties.
@@ -136,6 +167,6 @@ export type AnnotationTool<T extends PdfAnnotationObject = PdfAnnotationObject>
136
167
  selectAfterCreate?: boolean;
137
168
  /** Override whether this annotation type uses AP rendering before editing (default: true) */
138
169
  useAppearanceStream?: boolean;
139
- } & InsertUprightBehaviorFor<T>;
170
+ } & InsertUprightBehaviorFor<T> & InkBehaviorFor<T>;
140
171
  } & ClickBehaviorFor<T>;
141
172
  export {};