teamsync-pdf-viewer 1.3.4 → 1.4.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/CHANGELOG.md +25 -0
- package/dist/src/components/DocumentViewer.d.ts +8 -1
- package/dist/src/components/PageRenderer.d.ts +3 -1
- package/dist/src/components/SideBySideViewer.d.ts +2 -1
- package/dist/src/components/TeamSyncViewer.d.ts +13 -0
- package/dist/src/components/TextSelectionTooltip.d.ts +7 -0
- package/dist/src/core/ViewerInstance.d.ts +11 -0
- package/dist/src/core/types.d.ts +23 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/utils/clipboardUtils.d.ts +5 -0
- package/dist/src/utils/zoomUtils.d.ts +2 -2
- package/dist/style.css +1 -1
- package/dist/teamsync-pdf-viewer.js +1511 -1306
- package/dist/teamsync-pdf-viewer.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `teamsync-pdf-viewer` are documented here.
|
|
4
4
|
|
|
5
|
+
## [1.4.0] — 2026-09-04
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Text Selection & Copying Support**: Users can now select and copy text directly from PDF pages in the viewer.
|
|
9
|
+
- **Select & Pan Tool Modes**: Added `'select'` as a first-class `ToolMode`. Defaulted `activeTool` to `'select'` (matching Adobe Acrobat, Chrome, and PDF.js). Added "Select Text" (`MousePointer`) and "Pan Tool" (`Hand`) toggle buttons to the top toolbar. Added `defaultTool?: 'select' | 'pan'` and `enableTextSelection?: boolean` props to `WebViewerOptions` and `<TeamSyncViewer>`.
|
|
10
|
+
- **Triple-Layer Copy Workflows**:
|
|
11
|
+
- **Keyboard**: `Cmd+C` (macOS) / `Ctrl+C` (Windows/Linux) copies selected text to the clipboard.
|
|
12
|
+
- **Native Context Menu**: Right-clicking selected text preserves the native browser context menu ("Copy", "Look Up", "Search", "Translate").
|
|
13
|
+
- **Floating Quick-Copy Tooltip**: Rendered a sleek floating pill above active text selections with a `[Copy]` button and `✓ Copied!` visual feedback.
|
|
14
|
+
- **Public SDK APIs & Events**: Added `instance.getSelectedText(): string` and `instance.copySelectedText(): Promise<boolean>`, Apryse tool aliases in `instance.UI.setToolMode('select' | 'textSelect' | 'pan')`, and `textSelected` and `textCopied` events to `ViewerEventMap`.
|
|
15
|
+
- **Cross-Environment Clipboard Utility**: Exported `copyTextToClipboard` with modern `navigator.clipboard.writeText` and a hidden `document.execCommand('copy')` fallback for non-HTTPS and iframe environments.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Panning Drag Interference**: Drag-panning is now strictly scoped to `activeTool === 'pan'`, ensuring text selection click-and-drag is never hijacked.
|
|
19
|
+
- **SVG Overlay Pointer Events**: Configured SVG overlay to `pointerEvents: 'none'` in select and pan modes so clicks reach the text layer, while preserving `pointerEvents: 'all'` on individual annotation elements.
|
|
20
|
+
- **PDF.js v6 Text Layer CSS Variables**: Declared `--total-scale-factor: 1; --scale-factor: 1; --user-unit: 1; --min-font-size: 1; --scale-round-x: 1px; --scale-round-y: 1px;` on `.textLayer`, resolving collapsed 0px font sizes and heights. Styled `.textLayer span::selection` with transparent text so the underlying canvas raster remains crisp without double glyphs.
|
|
21
|
+
|
|
22
|
+
## [1.3.5] — 2026-09-04
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **Annotations Before Document Canvas**: Fixed bug where the SVG annotation overlay and transient citation highlights rendered synchronously over a still-blank white container on initial load, virtualized scroll (pages 2+), and post-open fit re-renders. Annotations now wait until the underlying page canvas has finished rendering its pixels before becoming visible.
|
|
26
|
+
- **`hideAnnotationsUntilPageRendered` Option**: Added `hideAnnotationsUntilPageRendered?: boolean` (defaults to `true`) across `WebViewerOptions`, `TeamSyncViewerProps`, and `DocumentViewerProps`.
|
|
27
|
+
- **`pageRendered` Lifecycle Event**: Added `pageRendered: { url: string; pageNumber: number }` to `ViewerEventMap` and `onPageRendered` callback to `TeamSyncViewerProps` and `DocumentViewerProps`, giving consumers a lifecycle hook whenever any page finishes canvas rendering.
|
|
28
|
+
- **Capped Zoom Level to 800%**: Changed `MAX_SCALE = 8.0` (800%), updated zoom stepping and boundary checks, and updated toolbar preset dropdown to cap at 800%.
|
|
29
|
+
|
|
5
30
|
## [1.3.4] — 2026-09-04
|
|
6
31
|
|
|
7
32
|
### Fixed
|
|
@@ -35,6 +35,8 @@ interface DocumentViewerProps {
|
|
|
35
35
|
onLoadError?: (error: Error, info: DocumentLoadErrorInfo) => void;
|
|
36
36
|
/** Fires once per loaded document, after the first page canvas has been painted. */
|
|
37
37
|
onFirstPageRendered?: (pageNumber: number) => void;
|
|
38
|
+
/** Fires whenever any page canvas has finished rendering. */
|
|
39
|
+
onPageRendered?: (pageNumber: number) => void;
|
|
38
40
|
onPageChange?: (pageNumber: number, numPages: number) => void;
|
|
39
41
|
pageTransition: 'continuous' | 'page-by-page';
|
|
40
42
|
pageLayout: 'single' | 'double' | 'cover-facing';
|
|
@@ -47,6 +49,11 @@ interface DocumentViewerProps {
|
|
|
47
49
|
page?: number;
|
|
48
50
|
transientHighlights?: TransientHighlight[];
|
|
49
51
|
permissions?: SDKPermissions;
|
|
52
|
+
/** Whether to hide annotations and transient highlights until the page canvas has finished rendering. Default: true. */
|
|
53
|
+
hideAnnotationsUntilPageRendered?: boolean;
|
|
54
|
+
enableTextSelection?: boolean;
|
|
55
|
+
defaultTool?: 'select' | 'pan';
|
|
56
|
+
showSelectionTooltip?: boolean;
|
|
50
57
|
}
|
|
51
|
-
export default function DocumentViewer({ leftSidebarOpen, rightSidebarOpen, activeTab, annotationManager, initialDoc, loadNonce, withCredentials, assets, sidebars, redactions, regexRedactions, scale, setScale, sidebarTab, setSidebarTab, onAnnotationsChange, onRedactionsChange, onDocumentLoaded, onLoadError, onFirstPageRendered, onPageChange, pageTransition, pageLayout, rotation, setRotation, watermark, watermarkText, enableAnnotations: _enableAnnotations, initialPage, page, transientHighlights, permissions }: DocumentViewerProps): React.JSX.Element;
|
|
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;
|
|
52
59
|
export {};
|
|
@@ -35,7 +35,9 @@ interface PageRendererProps {
|
|
|
35
35
|
onDiscardRedaction?: (redaction: Redaction) => void;
|
|
36
36
|
/** Called after the page canvas has been painted (used for first-page-rendered telemetry). */
|
|
37
37
|
onRendered?: (pageNum: number) => void;
|
|
38
|
+
/** Whether to hide annotations and transient highlights until the page canvas has finished rendering. Default: true. */
|
|
39
|
+
hideAnnotationsUntilPageRendered?: boolean;
|
|
38
40
|
}
|
|
39
|
-
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 }: PageRendererProps): React.JSX.Element;
|
|
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;
|
|
40
42
|
declare const PageRenderer: React.MemoExoticComponent<typeof PageRendererComponent>;
|
|
41
43
|
export default PageRenderer;
|
|
@@ -24,6 +24,7 @@ interface SideBySideViewerProps {
|
|
|
24
24
|
selectedDiffId?: string | null;
|
|
25
25
|
onSelectDiff?: (id: string) => void;
|
|
26
26
|
onScrollSync?: (scrollTop: number, scrollLeft: number) => void;
|
|
27
|
+
hideAnnotationsUntilPageRendered?: boolean;
|
|
27
28
|
}
|
|
28
|
-
export default function SideBySideViewer({ pdfDocA, pdfDocB, pageNum, scale, rotation, basePageDims, activeTab, activeTool, annotations, watermark, watermarkText, redactions, diffsA, diffsB, selectedDiffId, onSelectDiff }: SideBySideViewerProps): React.JSX.Element;
|
|
29
|
+
export default function SideBySideViewer({ pdfDocA, pdfDocB, pageNum, scale, rotation, basePageDims, activeTab, activeTool, annotations, watermark, watermarkText, redactions, diffsA, diffsB, selectedDiffId, onSelectDiff, hideAnnotationsUntilPageRendered }: SideBySideViewerProps): React.JSX.Element;
|
|
29
30
|
export {};
|
|
@@ -22,6 +22,11 @@ export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
|
|
|
22
22
|
url: string;
|
|
23
23
|
pageNumber: number;
|
|
24
24
|
}) => void;
|
|
25
|
+
/** Fires whenever any page canvas has finished rendering. */
|
|
26
|
+
onPageRendered?: (info: {
|
|
27
|
+
url: string;
|
|
28
|
+
pageNumber: number;
|
|
29
|
+
}) => void;
|
|
25
30
|
/** Fires (in addition to onDocumentLoadError) when the document is password protected. */
|
|
26
31
|
onPasswordRequired?: (info: {
|
|
27
32
|
url: string;
|
|
@@ -30,6 +35,14 @@ export interface TeamSyncViewerProps extends Omit<WebViewerOptions, 'path'> {
|
|
|
30
35
|
onAnnotationsChange?: (annotations: Annotation[]) => void;
|
|
31
36
|
/** Fires whenever transient highlights change. */
|
|
32
37
|
onTransientHighlightsChange?: (highlights: TransientHighlight[]) => void;
|
|
38
|
+
/** Fires whenever the user selects text within the document. */
|
|
39
|
+
onTextSelected?: (info: {
|
|
40
|
+
text: string;
|
|
41
|
+
}) => void;
|
|
42
|
+
/** Fires whenever text is copied from the document. */
|
|
43
|
+
onTextCopied?: (info: {
|
|
44
|
+
text: string;
|
|
45
|
+
}) => void;
|
|
33
46
|
className?: string;
|
|
34
47
|
style?: React.CSSProperties;
|
|
35
48
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
interface TextSelectionTooltipProps {
|
|
3
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
4
|
+
onCopy?: (text: string) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare const TextSelectionTooltip: React.FC<TextSelectionTooltipProps>;
|
|
7
|
+
export default TextSelectionTooltip;
|
|
@@ -103,6 +103,15 @@ export declare class WebViewerInstance {
|
|
|
103
103
|
* Uses the bytes of the loaded document; never re-fetches the URL.
|
|
104
104
|
*/
|
|
105
105
|
getFileData(options?: ExportOptions): Promise<Uint8Array>;
|
|
106
|
+
/**
|
|
107
|
+
* Returns the currently selected text string from the document viewer, or an empty string if nothing is selected.
|
|
108
|
+
*/
|
|
109
|
+
getSelectedText(): string;
|
|
110
|
+
/**
|
|
111
|
+
* Copies the currently selected text to the system clipboard.
|
|
112
|
+
* Resolves to true if copying succeeded, false otherwise.
|
|
113
|
+
*/
|
|
114
|
+
copySelectedText(): Promise<boolean>;
|
|
106
115
|
readonly UI: {
|
|
107
116
|
/** Theming is not implemented; kept for API compatibility. */
|
|
108
117
|
setTheme: (_theme: string) => void;
|
|
@@ -114,6 +123,8 @@ export declare class WebViewerInstance {
|
|
|
114
123
|
disableElements: (elements: string[]) => void;
|
|
115
124
|
setActiveLeftPanel: (panel: string) => void;
|
|
116
125
|
setToolMode: (tool: string | null) => void;
|
|
126
|
+
getSelectedText: () => string;
|
|
127
|
+
copySelectedText: () => Promise<boolean>;
|
|
117
128
|
fitWidth: () => void;
|
|
118
129
|
fitPage: () => void;
|
|
119
130
|
fitToWidth: () => void;
|
package/dist/src/core/types.d.ts
CHANGED
|
@@ -54,6 +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
58
|
/**
|
|
58
59
|
* Options accepted by `createWebViewer()` (and the deprecated `WebViewer()` alias).
|
|
59
60
|
* Every option is also available as a prop on `<TeamSyncViewer>`.
|
|
@@ -100,6 +101,18 @@ export interface WebViewerOptions {
|
|
|
100
101
|
leftPanelOpen?: boolean;
|
|
101
102
|
/** Focus the viewer on mount so keyboard shortcuts work immediately. Default false. */
|
|
102
103
|
autoFocus?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Hide SVG annotation overlays and transient highlights until the underlying page canvas has finished rendering.
|
|
106
|
+
* Prevents annotations from rendering over a blank white page container on initial load, scroll, or fit re-render.
|
|
107
|
+
* Default true.
|
|
108
|
+
*/
|
|
109
|
+
hideAnnotationsUntilPageRendered?: boolean;
|
|
110
|
+
/** Allow selecting text from PDF pages (default true). */
|
|
111
|
+
enableTextSelection?: boolean;
|
|
112
|
+
/** Initial tool mode on load. Defaults to 'select'. */
|
|
113
|
+
defaultTool?: 'select' | 'pan';
|
|
114
|
+
/** Show floating quick-action copy badge above selected text (default true). */
|
|
115
|
+
showSelectionTooltip?: boolean;
|
|
103
116
|
}
|
|
104
117
|
/** Events available through `instance.on(type, listener)`. */
|
|
105
118
|
export interface ViewerEventMap {
|
|
@@ -116,6 +129,10 @@ export interface ViewerEventMap {
|
|
|
116
129
|
url: string;
|
|
117
130
|
pageNumber: number;
|
|
118
131
|
};
|
|
132
|
+
pageRendered: {
|
|
133
|
+
url: string;
|
|
134
|
+
pageNumber: number;
|
|
135
|
+
};
|
|
119
136
|
pageChanged: {
|
|
120
137
|
pageNumber: number;
|
|
121
138
|
numPages: number;
|
|
@@ -131,6 +148,12 @@ export interface ViewerEventMap {
|
|
|
131
148
|
toolChanged: {
|
|
132
149
|
tool: string | null;
|
|
133
150
|
};
|
|
151
|
+
textSelected: {
|
|
152
|
+
text: string;
|
|
153
|
+
};
|
|
154
|
+
textCopied: {
|
|
155
|
+
text: string;
|
|
156
|
+
};
|
|
134
157
|
destroy: Record<string, never>;
|
|
135
158
|
}
|
|
136
159
|
export type ViewerEventType = keyof ViewerEventMap;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -17,7 +17,9 @@ export { ViewerBus } from './core/eventBus';
|
|
|
17
17
|
export type { BusListener } from './core/eventBus';
|
|
18
18
|
export { buildPdfBytes, MAX_EXPORT_BYTES } from './core/export';
|
|
19
19
|
export type { ExportInput, ExportOptions } from './core/export';
|
|
20
|
-
export type { WebViewerOptions, Redaction, WatermarkOptions, SDKPermissions, ViewerUser, InitialScale, ViewerEventMap, ViewerEventType, } from './core/types';
|
|
20
|
+
export type { WebViewerOptions, Redaction, WatermarkOptions, SDKPermissions, ViewerUser, InitialScale, ViewerEventMap, ViewerEventType, ToolMode, } from './core/types';
|
|
21
|
+
export { copyTextToClipboard } from './utils/clipboardUtils';
|
|
22
|
+
export { TextSelectionTooltip } from './components/TextSelectionTooltip';
|
|
21
23
|
export type { Annotation, AnnotationType, AnnotationPoint, AnnotationInput } from './annotations/types';
|
|
22
24
|
export { AnnotationManager } from './annotations/AnnotationManager';
|
|
23
25
|
export type { AnnotationAction, AnnotationChangedEvent, CommitOptions, ViewerUserInfo } from './annotations/AnnotationManager';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* © 2026 AngelBot Ai Pvt Ltd. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
export declare const MIN_SCALE = 0.1;
|
|
5
|
-
export declare const MAX_SCALE =
|
|
5
|
+
export declare const MAX_SCALE = 8;
|
|
6
6
|
export declare const isMobileOrTablet: () => boolean;
|
|
7
7
|
export declare const isSafariOrMobile: () => boolean;
|
|
8
8
|
export declare const MAX_CANVAS_DIM = 4096;
|
|
@@ -13,7 +13,7 @@ export declare const MAX_CANVAS_PIXELS_MOBILE = 4194304;
|
|
|
13
13
|
* Calculates the next step when zooming in.
|
|
14
14
|
* - Below 200%: steps by +25%
|
|
15
15
|
* - 200% to 500%: steps by +50%
|
|
16
|
-
* - 500% to
|
|
16
|
+
* - 500% to 800%: steps by +100%
|
|
17
17
|
*/
|
|
18
18
|
export declare function calculateNextZoomIn(currentScale: number, maxScale?: number): number;
|
|
19
19
|
/**
|