teamsync-pdf-viewer 1.4.0 → 1.5.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  All notable changes to `teamsync-pdf-viewer` are documented here.
4
4
 
5
+ ## [1.5.1] — 2026-09-06
6
+
7
+ ### Added
8
+ - **`redactionsApplied` & `redactionsChanged` Events**: Added typed `redactionsApplied: { redactions: Redaction[] }` and `redactionsChanged: { redactions: Redaction[] }` events to `ViewerEventMap` available via `instance.on()`.
9
+ - **Public Redaction Callbacks**: Added `onRedactionsApplied?: (redactions: Redaction[]) => void` and `onRedactionsChange?: (redactions: Redaction[]) => void` props to `<TeamSyncViewer>` and `WebViewerOptions`.
10
+ - **Apply Confirmation Hook**: Threaded `onRedactionsApplied` through `DocumentViewerProps`, firing once per user click of Apply in the confirmation modal with the full combined list of applied redactions.
11
+ - **Public `getRedactions()` API**: Added `instance.getRedactions(): Redaction[]` to `WebViewerInstance` mirroring `getAnnotations()`, returning the live combined redaction list.
12
+
13
+ ## [1.5.0] — 2026-09-05
14
+
15
+ ### Added
16
+ - **Undo & Redo Annotation Actions**: Added dedicated Undo and Redo buttons to the Annotate toolbar with live state reflection bound to history, alongside existing keyboard shortcuts (`Cmd+Z`/`Ctrl+Z` and `Cmd+Shift+Z`/`Ctrl+Y`).
17
+ - **Underline, Strikeout & Squiggly Tools**: Added first-class text markup annotations with toolbar tools, stroke width and color controls, drag creation, selection tooltip quick actions, SVG rendering (straight lines and sinusoidal waves), full XFDF export/import roundtrip, and PDF export baking via `pdf-lib`.
18
+ - **Text Annotation Automatic Word-Wrapping**: Text annotations now automatically wrap multi-line text cleanly inside SVG `<foreignObject>` containers (`word-break: break-word`, `overflow-wrap: break-word`, `white-space: pre-wrap`) and in baked PDF exports via dynamic text wrapping.
19
+ - **Interactive 8-Handle Text Resizing**: Text annotations now feature an interactive selection bounding box with 8 resize handles (`nw`, `n`, `ne`, `e`, `se`, `s`, `sw`, `w`) with directional cursors, real-time live text reflow during drag, and single-step undo history.
20
+ - **Quick-Markup Selection Tooltip**: Extended the floating selection tooltip with `[Highlight]`, `[Underline]`, `[Strikeout]`, and `[Squiggly]` quick actions.
21
+
5
22
  ## [1.4.0] — 2026-09-04
6
23
 
7
24
  ### Added
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ![TeamSync PDF Viewer UI](https://raw.githubusercontent.com/angelbot-ai/TeamSync-PDF-Viewer/main/docs/images/viewer_ui.png)
6
6
 
7
- ### **100% Open Source. 100% Client-Side. Enterprise PDF Engine.**
7
+ ### **100% Open Source. 100% Client-Side. Enterprise SDK.**
8
8
 
9
9
  [![License: CPAL-1.0](https://img.shields.io/badge/License-CPAL--1.0-blue.svg)](LICENSE)
10
10
  [![Live Demo](https://img.shields.io/badge/Live%20Demo-pdfviewer.teamsync.com-000000.svg)](https://pdfviewer.teamsync.com/)
@@ -25,7 +25,7 @@ Try the **[Interactive Live Demo](https://pdfviewer.teamsync.com/)** or integrat
25
25
  Traditional commercial PDF viewers force developers into expensive per-domain licenses, opaque sales calls, and heavy server-side processing dependencies. **TeamSync PDF Viewer** is built from the ground up to solve these pain points.
26
26
 
27
27
  - 💰 **Zero-Cost, Transparent Licensing**: Uncapped usage, no per-server fees, and no commercial paywalls. 100% free and open-source under CPAL 1.0.
28
- - ⚡ **100% Client-Side WebAssembly**: Documents never leave the browser sandbox. Process, redact, and render PDFs entirely on the client—guaranteeing instant **HIPAA**, **GDPR**, and **FINRA** compliance.
28
+ - ⚡ **100% Client-Side WebAssembly**: Documents never leave the browser sandbox. Process, redact, and render PDFs entirely on the client.
29
29
  - 🔌 **Universal WebViewer API**: Clean, intuitive `WebViewer({...})` API interface that makes integrating into your web applications effortless.
30
30
  - 🎨 **Headless & Customizable**: Built for modern React 19 SPA lifecycles. No bloated iFrames to fight—customize toolbars, sidebars, context menus, and controls natively.
31
31
 
@@ -84,10 +84,10 @@ Everything you need to build collaborative, secure document workflows.
84
84
  - **Notes & Callouts**: Sticky notes, callout text boxes with directional arrows, and text annotations.
85
85
  - **Interactive Hyperlinks**: Create internal page-jump links (`#page=N`) or external web URL links directly on document selections.
86
86
 
87
- ### 🛡️ Military-Grade Secure Redaction
87
+ ### 🛡️ Secure Redaction
88
88
  - **Binary-Level Data Obliteration**: We don't just place black boxes over text—redactions are permanently rasterized and burned into the underlying PDF vector structure.
89
89
  - **Text Layer Sanitization**: Redacted text is automatically stripped from the DOM `textLayer` and PDF content streams, preventing copy/paste extraction and search indexing.
90
- - **Automatic Regex Redactions**: Programmatically locate and redact sensitive PII (Aadhaar numbers, SSNs, credit cards, dates of birth) in a single click.
90
+ - **Automatic Regex Redactions**: Programmatically locate and redact sensitive PII in a single click.
91
91
  - **Discard Unapplied Redactions**: Easily discard individual pending redactions or bulk-discard all unapplied redaction marks before committing.
92
92
 
93
93
  ### 📐 Dynamic Layout & Viewport Controls
@@ -6,7 +6,7 @@
6
6
  * /Rotate applied (top-left origin, PDF points). UI rotation applied by the viewer is composed on
7
7
  * top of this space at render time, so stored annotations are independent of the current view.
8
8
  */
9
- export type AnnotationType = 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'freehand' | 'text' | 'note' | 'callout' | 'signature' | 'highlight' | 'digital_signature_placeholder' | 'link'
9
+ export type AnnotationType = 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'freehand' | 'text' | 'note' | 'callout' | 'signature' | 'highlight' | 'underline' | 'strikeout' | 'squiggly' | 'digital_signature_placeholder' | 'link'
10
10
  /**
11
11
  * An annotation imported from XFDF that this viewer cannot edit or render natively (e.g.
12
12
  * underline, squiggly, polygon, redaction). It is drawn as a read-only outline at its bounding
@@ -31,6 +31,8 @@ interface DocumentViewerProps {
31
31
  onAnnotationsChange?: (annotations: Annotation[]) => void;
32
32
  /** Reports the combined (prop + regex + manual) redaction list whenever it changes. */
33
33
  onRedactionsChange?: (redactions: Redaction[]) => void;
34
+ /** Fires once per user click of Apply in the confirmation modal with all applied redactions. */
35
+ onRedactionsApplied?: (redactions: Redaction[]) => void;
34
36
  onDocumentLoaded?: (doc: pdfjsLib.PDFDocumentProxy, url: string) => void;
35
37
  onLoadError?: (error: Error, info: DocumentLoadErrorInfo) => void;
36
38
  /** Fires once per loaded document, after the first page canvas has been painted. */
@@ -55,5 +57,5 @@ interface DocumentViewerProps {
55
57
  defaultTool?: 'select' | 'pan';
56
58
  showSelectionTooltip?: boolean;
57
59
  }
58
- export default function DocumentViewer({ leftSidebarOpen, rightSidebarOpen, activeTab, annotationManager, initialDoc, loadNonce, withCredentials, assets, sidebars, redactions, regexRedactions, scale, setScale, sidebarTab, setSidebarTab, onAnnotationsChange, onRedactionsChange, onDocumentLoaded, onLoadError, onFirstPageRendered, onPageRendered, onPageChange, pageTransition, pageLayout, rotation, setRotation, watermark, watermarkText, enableAnnotations: _enableAnnotations, initialPage, page, transientHighlights, permissions, hideAnnotationsUntilPageRendered, enableTextSelection, defaultTool, showSelectionTooltip }: DocumentViewerProps): React.JSX.Element;
60
+ export default function DocumentViewer({ leftSidebarOpen, rightSidebarOpen, activeTab, annotationManager, initialDoc, loadNonce, withCredentials, assets, sidebars, redactions, regexRedactions, scale, setScale, sidebarTab, setSidebarTab, onAnnotationsChange, onRedactionsChange, onRedactionsApplied, onDocumentLoaded, onLoadError, onFirstPageRendered, onPageRendered, onPageChange, pageTransition, pageLayout, rotation, setRotation, watermark, watermarkText, enableAnnotations: _enableAnnotations, initialPage, page, transientHighlights, permissions, hideAnnotationsUntilPageRendered, enableTextSelection, defaultTool, showSelectionTooltip }: DocumentViewerProps): React.JSX.Element;
59
61
  export {};
@@ -27,6 +27,9 @@ interface PageRendererProps {
27
27
  onMouseMove: (e: React.MouseEvent<Element>, pageNum: number) => void;
28
28
  onMouseUp: (e: React.MouseEvent<Element>, pageNum: number) => void;
29
29
  onAnnotationClick: (id: string, e: React.MouseEvent) => void;
30
+ onAnnotationDoubleClick?: (id: string, e: React.MouseEvent) => void;
31
+ onStartResize?: (id: string, handle: string, e: React.MouseEvent, pageNum: number) => void;
32
+ onStartMove?: (id: string, e: React.MouseEvent, pageNum: number) => void;
30
33
  onAnnotationMouseEnter: (id: string) => void;
31
34
  onClearSelection: () => void;
32
35
  watermark?: WatermarkOptions;
@@ -38,6 +41,6 @@ interface PageRendererProps {
38
41
  /** Whether to hide annotations and transient highlights until the page canvas has finished rendering. Default: true. */
39
42
  hideAnnotationsUntilPageRendered?: boolean;
40
43
  }
41
- declare function PageRendererComponent({ pageNum, pdfDoc, scale, rotation, containerWidth: _containerWidth, containerHeight: _containerHeight, scrollTop: _scrollTop, scrollLeft: _scrollLeft, pageTop, pageLeft, basePageWidth, basePageHeight, activeTab, activeTool, annotations, selectedAnnotationId, activeSearchResult, transientHighlights, onMouseDown, onMouseMove, onMouseUp, onAnnotationClick, onAnnotationMouseEnter, onClearSelection, watermark, watermarkText, redactions, onDiscardRedaction, onRendered, hideAnnotationsUntilPageRendered }: PageRendererProps): React.JSX.Element;
44
+ declare function PageRendererComponent({ pageNum, pdfDoc, scale, rotation, containerWidth: _containerWidth, containerHeight: _containerHeight, scrollTop: _scrollTop, scrollLeft: _scrollLeft, pageTop, pageLeft, basePageWidth, basePageHeight, activeTab, activeTool, annotations, selectedAnnotationId, activeSearchResult, transientHighlights, onMouseDown, onMouseMove, onMouseUp, onAnnotationClick, onAnnotationDoubleClick, onStartResize, onStartMove, onAnnotationMouseEnter, onClearSelection, watermark, watermarkText, redactions, onDiscardRedaction, onRendered, hideAnnotationsUntilPageRendered }: PageRendererProps): React.JSX.Element;
42
45
  declare const PageRenderer: React.MemoExoticComponent<typeof PageRendererComponent>;
43
46
  export default PageRenderer;
@@ -1,7 +1,7 @@
1
1
  import { default as React } from 'react';
2
2
  import { DocumentLoadErrorInfo } from './DocumentViewer';
3
3
  import { WebViewerInstance } from '../core/ViewerInstance';
4
- import { WebViewerOptions, TransientHighlight } from '../core/types';
4
+ import { WebViewerOptions, Redaction, TransientHighlight } from '../core/types';
5
5
  import { Annotation } from '../annotations/types';
6
6
  export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
7
7
  /** URL of the PDF to display. Alias of `initialDoc`; `fileUrl` wins when both are set. */
@@ -33,6 +33,10 @@ export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
33
33
  }) => void;
34
34
  onPageChange?: (pageNumber: number, numPages: number) => void;
35
35
  onAnnotationsChange?: (annotations: Annotation[]) => void;
36
+ /** Fires whenever pending or applied redactions change in the viewer. */
37
+ onRedactionsChange?: (redactions: Redaction[]) => void;
38
+ /** Fires once per user click of Apply in the confirmation modal with all applied redactions. */
39
+ onRedactionsApplied?: (redactions: Redaction[]) => void;
36
40
  /** Fires whenever transient highlights change. */
37
41
  onTransientHighlightsChange?: (highlights: TransientHighlight[]) => void;
38
42
  /** Fires whenever the user selects text within the document. */
@@ -2,6 +2,7 @@ import { default as React } from 'react';
2
2
  interface TextSelectionTooltipProps {
3
3
  containerRef: React.RefObject<HTMLDivElement | null>;
4
4
  onCopy?: (text: string) => void;
5
+ onAnnotateSelection?: (type: 'highlight' | 'underline' | 'strikeout' | 'squiggly') => void;
5
6
  }
6
7
  export declare const TextSelectionTooltip: React.FC<TextSelectionTooltipProps>;
7
8
  export default TextSelectionTooltip;
@@ -96,6 +96,8 @@ export declare class WebViewerInstance {
96
96
  tooltip?: string;
97
97
  }): Promise<SearchResult | null>;
98
98
  getAnnotations(): Annotation[];
99
+ /** Get the current list of redactions (pending and applied). */
100
+ getRedactions(): Redaction[];
99
101
  /** Print the exported document (annotations, redactions and watermark baked in). */
100
102
  print(): void;
101
103
  /**
@@ -54,7 +54,7 @@ export interface ViewerUser {
54
54
  name: string;
55
55
  }
56
56
  export type InitialScale = number | 'fit-width' | 'fit-page';
57
- export type ToolMode = 'select' | 'pan' | 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'freehand' | 'highlight' | 'text' | 'eraser' | 'note' | 'callout' | 'signature' | 'digital_signature' | 'link' | 'redaction' | null;
57
+ export type ToolMode = 'select' | 'pan' | 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'freehand' | 'highlight' | 'underline' | 'strikeout' | 'squiggly' | 'text' | 'eraser' | 'note' | 'callout' | 'signature' | 'digital_signature' | 'link' | 'redaction' | null;
58
58
  /**
59
59
  * Options accepted by `createWebViewer()` (and the deprecated `WebViewer()` alias).
60
60
  * Every option is also available as a prop on `<TeamSyncViewer>`.
@@ -113,6 +113,10 @@ export interface WebViewerOptions {
113
113
  defaultTool?: 'select' | 'pan';
114
114
  /** Show floating quick-action copy badge above selected text (default true). */
115
115
  showSelectionTooltip?: boolean;
116
+ /** Fires whenever pending or applied redactions change in the viewer. */
117
+ onRedactionsChange?: (redactions: Redaction[]) => void;
118
+ /** Fires once per user click of Apply in the confirmation modal with all applied redactions. */
119
+ onRedactionsApplied?: (redactions: Redaction[]) => void;
116
120
  }
117
121
  /** Events available through `instance.on(type, listener)`. */
118
122
  export interface ViewerEventMap {
@@ -142,6 +146,12 @@ export interface ViewerEventMap {
142
146
  };
143
147
  /** Granular add / modify / delete (with the `imported` flag) from the AnnotationManager. */
144
148
  annotationChanged: AnnotationChangedEvent;
149
+ redactionsChanged: {
150
+ redactions: Redaction[];
151
+ };
152
+ redactionsApplied: {
153
+ redactions: Redaction[];
154
+ };
145
155
  transientHighlightsChanged: {
146
156
  highlights: TransientHighlight[];
147
157
  };