@progress/kendo-react-pdf-viewer 5.10.0-dev.202211241147

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.
@@ -0,0 +1,78 @@
1
+ import { SaveOptions } from '@progress/kendo-file-saver';
2
+ import { PDFPageProxy, PDFDocumentProxy } from 'pdfjs-dist';
3
+ import { TypedArray } from 'pdfjs-dist/types/src/display/api';
4
+ /**
5
+ * @hidden
6
+ */
7
+ export declare type DoneFn = (result: {
8
+ pdfPages: PDFPageProxy[];
9
+ pdfDoc: PDFDocumentProxy;
10
+ }) => void;
11
+ /**
12
+ * @hidden
13
+ */
14
+ export declare type ErrorFn = (e?: any) => void;
15
+ /**
16
+ * @hidden
17
+ */
18
+ export interface PDFReadParameters {
19
+ url?: string;
20
+ data?: string;
21
+ arrayBuffer?: ArrayBuffer;
22
+ typedArray?: TypedArray;
23
+ error: ErrorFn;
24
+ }
25
+ /**
26
+ * @hidden
27
+ */
28
+ export interface PDFReadOptions extends PDFReadParameters {
29
+ dom: HTMLDivElement;
30
+ zoom: number;
31
+ done: DoneFn;
32
+ }
33
+ /**
34
+ * @hidden
35
+ */
36
+ export interface PDFReloadParameters {
37
+ pdfDoc: PDFDocumentProxy;
38
+ zoom: number;
39
+ dom: HTMLElement;
40
+ done: (pdfPages: PDFPageProxy[]) => void;
41
+ error: ErrorFn;
42
+ }
43
+ /**
44
+ * @hidden
45
+ */
46
+ export declare const DEFAULT_ZOOM_LEVEL = 1.25;
47
+ /**
48
+ * @hidden
49
+ */
50
+ export declare const download: (options: PDFReadParameters, fileName: string | undefined, saveOptions: SaveOptions | undefined, onDownload: (blob: Blob, fileName: string, saveOptions: SaveOptions) => boolean) => void;
51
+ /**
52
+ * @hidden
53
+ */
54
+ export declare const loadPDF: (options: PDFReadOptions) => void;
55
+ /**
56
+ * @hidden
57
+ */
58
+ export declare const reloadDocument: (params: PDFReloadParameters) => void;
59
+ /**
60
+ * @hidden
61
+ */
62
+ export declare const print: (pages: PDFPageProxy[], done: () => void, error: ErrorFn) => void;
63
+ /**
64
+ * @hidden
65
+ */
66
+ export declare const goToNextSearchMatch: (ref: any) => void;
67
+ /**
68
+ * @hidden
69
+ */
70
+ export declare const goToPreviousSearchMatch: (ref: any) => void;
71
+ /**
72
+ * @hidden
73
+ */
74
+ export declare const calculateZoomLevel: (zoomLevel: number, zoomLevelType: string, currentZoom: number, dom: HTMLDivElement) => number;
75
+ /**
76
+ * @hidden
77
+ */
78
+ export declare const removeChildren: (dom: HTMLElement) => void;
@@ -0,0 +1,240 @@
1
+ import { saveAs } from '@progress/kendo-file-saver';
2
+ import { getDocument, renderTextLayer } from 'pdfjs-dist';
3
+ /**
4
+ * @hidden
5
+ */
6
+ export const DEFAULT_ZOOM_LEVEL = 1.25;
7
+ const parsePdfFromBase64String = (base64String) => {
8
+ return atob(base64String.replace(/^(data:application\/pdf;base64,)/ig, ''));
9
+ };
10
+ const getDocumentParameters = (options) => {
11
+ let params = { verbosity: 0 };
12
+ if (typeof options.data === 'string') {
13
+ params.data = parsePdfFromBase64String(options.data);
14
+ }
15
+ else if (typeof options.url === 'string') {
16
+ params.url = options.url;
17
+ }
18
+ else if (options.arrayBuffer instanceof ArrayBuffer) {
19
+ params = options.arrayBuffer;
20
+ }
21
+ else if (options.typedArray) {
22
+ params = options.typedArray;
23
+ }
24
+ return params;
25
+ };
26
+ /**
27
+ * @hidden
28
+ */
29
+ export const download = (options, fileName = 'Document', saveOptions = {}, onDownload) => {
30
+ const params = getDocumentParameters(options);
31
+ getDocument(params).promise
32
+ .then((pdf) => pdf.getData())
33
+ .then((data) => new Blob([data], { type: 'application/pdf' }))
34
+ .then((blob) => {
35
+ if (!onDownload(blob, fileName, saveOptions)) {
36
+ saveAs(blob, fileName, saveOptions);
37
+ }
38
+ })
39
+ .catch((reason) => { options.error(reason); });
40
+ };
41
+ /**
42
+ * @hidden
43
+ */
44
+ export const loadPDF = (options) => {
45
+ const params = getDocumentParameters(options);
46
+ const { dom, zoom, done, error } = options;
47
+ getDocument(params).promise.then((pdfDoc) => {
48
+ const pages = [];
49
+ for (let i = 1; i <= pdfDoc.numPages; i++) {
50
+ pages.push(pdfDoc.getPage(i));
51
+ }
52
+ return { pages, pdfDoc };
53
+ }).then(({ pages, pdfDoc }) => {
54
+ Promise.all(pages)
55
+ .then(all => all.map(page => {
56
+ dom.appendChild(renderPage(page, zoom, error));
57
+ return page;
58
+ }))
59
+ .then((pdfPages) => {
60
+ done({ pdfPages, pdfDoc });
61
+ }).catch((reason) => { options.error(reason); });
62
+ }).catch((reason) => { options.error(reason); });
63
+ };
64
+ /**
65
+ * @hidden
66
+ */
67
+ export const reloadDocument = (params) => {
68
+ const { pdfDoc, zoom, dom, done, error } = params;
69
+ const pages = [];
70
+ for (let i = 1; i <= pdfDoc.numPages; i++) {
71
+ pages.push(pdfDoc.getPage(i));
72
+ }
73
+ Promise.all(pages)
74
+ .then(all => all.map(page => {
75
+ dom.appendChild(renderPage(page, zoom, error));
76
+ return page;
77
+ }))
78
+ .then(done)
79
+ .catch(error);
80
+ };
81
+ /**
82
+ * @hidden
83
+ */
84
+ export const print = (pages, done, error) => {
85
+ const dom = document.createElement('div');
86
+ let dones = pages.map(() => false);
87
+ pages.forEach((page, index) => {
88
+ const viewport = renderCanvas(page, (el) => {
89
+ dom.appendChild(el);
90
+ dones[index] = true;
91
+ if (dones.every(Boolean)) {
92
+ openPrintDialog(dom, viewport.width, viewport.height, done, error);
93
+ }
94
+ }, error);
95
+ });
96
+ };
97
+ const openPrintDialog = (dom, width, height, done, onError) => {
98
+ const printDialog = window.open('', '', 'innerWidth=' + width + ',innerHeight=' + height + 'location=no,titlebar=no,toolbar=no');
99
+ if (!printDialog || !printDialog.document) {
100
+ onError();
101
+ return;
102
+ }
103
+ if (printDialog) {
104
+ printDialog.document.body.appendChild(dom);
105
+ printDialog.focus();
106
+ setTimeout(() => {
107
+ printDialog.print();
108
+ done();
109
+ }, 0);
110
+ const onAfterPrint = () => {
111
+ printDialog.removeEventListener('afterprint', onAfterPrint);
112
+ printDialog.close();
113
+ };
114
+ printDialog.addEventListener('afterprint', onAfterPrint);
115
+ }
116
+ };
117
+ const renderCanvas = (page, done, error) => {
118
+ const viewport = page.getViewport({ scale: DEFAULT_ZOOM_LEVEL });
119
+ const styles = {};
120
+ const pageElement = createElement('div', '', styles);
121
+ const canvas = createElement('canvas', '', { width: '100%', height: '100%' });
122
+ const canvasContext = canvas.getContext('2d');
123
+ canvas.height = viewport.height;
124
+ canvas.width = viewport.width;
125
+ pageElement.appendChild(canvas);
126
+ page.render({ canvasContext, viewport }).promise.then(() => {
127
+ const printContent = new Image();
128
+ printContent.src = canvas.toDataURL();
129
+ pageElement.removeChild(canvas);
130
+ pageElement.appendChild(printContent);
131
+ printContent.width = canvas.width;
132
+ printContent.height = canvas.height;
133
+ const onload = () => {
134
+ printContent.removeEventListener('load', onload);
135
+ done(pageElement);
136
+ };
137
+ printContent.addEventListener('load', onload);
138
+ }).catch(error);
139
+ return viewport;
140
+ };
141
+ const createElement = function (name, className, styles) {
142
+ const element = document.createElement(name);
143
+ if (className) {
144
+ element.className = className;
145
+ }
146
+ Object.keys(styles).forEach(key => element.style[key] = styles[key]);
147
+ return element;
148
+ };
149
+ const renderPage = (page, zoom, error) => {
150
+ const viewport = page.getViewport({ scale: zoom });
151
+ const styles = { width: viewport.width + 'px', height: viewport.height + 'px' };
152
+ const pageElement = createElement('div', 'k-page', styles);
153
+ const canvas = createElement('canvas', '', { width: '100%', height: '100%' });
154
+ const canvasContext = canvas.getContext('2d');
155
+ canvas.height = viewport.height;
156
+ canvas.width = viewport.width;
157
+ pageElement.appendChild(canvas);
158
+ page.render({ canvasContext, viewport }).promise.then(() => {
159
+ page.getTextContent().then((textContent) => {
160
+ const textLayer = createElement('div', 'k-text-layer', styles);
161
+ renderTextLayer({
162
+ textContent: textContent,
163
+ container: textLayer,
164
+ viewport: viewport,
165
+ textDivs: []
166
+ }).promise.then(() => {
167
+ pageElement.appendChild(textLayer);
168
+ }).catch(error);
169
+ });
170
+ }).catch(error);
171
+ return pageElement;
172
+ };
173
+ const searchMatchScrollLeftOffset = 0;
174
+ const searchMatchScrollTopOffset = -64;
175
+ const scrollToSearchMatch = (matchElement, ref) => {
176
+ if (!matchElement) {
177
+ return;
178
+ }
179
+ const closestCharElement = matchElement.closest('.k-text-char');
180
+ const closestTextElement = closestCharElement ?
181
+ closestCharElement.closest('span[role=\'presentation\']') :
182
+ null;
183
+ if (!closestTextElement) {
184
+ return;
185
+ }
186
+ const closestPageElement = closestTextElement.closest('.k-page');
187
+ if (!closestPageElement) {
188
+ return;
189
+ }
190
+ const scrollLeft = closestPageElement.offsetLeft +
191
+ (-1) * ref.scroller.element.offsetLeft +
192
+ closestTextElement.offsetLeft + searchMatchScrollLeftOffset;
193
+ const scrollTop = closestPageElement.offsetTop +
194
+ (-1) * ref.scroller.element.offsetTop +
195
+ closestTextElement.offsetTop + searchMatchScrollTopOffset;
196
+ ref.scroller.scrollTo(scrollLeft, scrollTop, { trackScrollEvent: false });
197
+ };
198
+ /**
199
+ * @hidden
200
+ */
201
+ export const goToNextSearchMatch = (ref) => {
202
+ ref.search.markNextMatch();
203
+ const matchElement = ref.search.getActiveMatchElement();
204
+ scrollToSearchMatch(matchElement, ref);
205
+ };
206
+ /**
207
+ * @hidden
208
+ */
209
+ export const goToPreviousSearchMatch = (ref) => {
210
+ ref.search.markPreviousMatch();
211
+ const matchElement = ref.search.getActiveMatchElement();
212
+ scrollToSearchMatch(matchElement, ref);
213
+ };
214
+ /**
215
+ * @hidden
216
+ */
217
+ export const calculateZoomLevel = (zoomLevel, zoomLevelType, currentZoom, dom) => {
218
+ const documentContainer = dom.closest('.k-pdf-viewer-canvas');
219
+ const page = dom.querySelector('.k-page');
220
+ const pageSize = { width: page.offsetWidth, height: page.offsetHeight };
221
+ let calculatedZoomLevel = zoomLevel;
222
+ if (zoomLevelType === 'ActualWidth') {
223
+ calculatedZoomLevel = 1;
224
+ }
225
+ else if (zoomLevelType === 'FitToWidth') {
226
+ calculatedZoomLevel = (documentContainer.offsetWidth / (pageSize.width / currentZoom));
227
+ }
228
+ else if (zoomLevelType === 'FitToPage') {
229
+ calculatedZoomLevel = (documentContainer.offsetHeight / (pageSize.height / currentZoom));
230
+ }
231
+ return calculatedZoomLevel;
232
+ };
233
+ /**
234
+ * @hidden
235
+ */
236
+ export const removeChildren = (dom) => {
237
+ while (dom.firstChild) {
238
+ dom.removeChild(dom.firstChild);
239
+ }
240
+ };
@@ -0,0 +1,138 @@
1
+ import * as React from 'react';
2
+ import { Toolbar } from '@progress/kendo-react-buttons';
3
+ import { SaveOptions } from '@progress/kendo-file-saver';
4
+ import { TypedArray } from 'pdfjs-dist/types/src/display/api';
5
+ import 'pdfjs-dist/build/pdf.worker.entry';
6
+ interface PDFViewerEvent {
7
+ /**
8
+ * The event target object.
9
+ */
10
+ target: PDFViewerHandle;
11
+ }
12
+ /**
13
+ * The KendoReact [PDFViewer]({% slug api_pdf-viewer_pdfviewer %}) ErrorEvent object.
14
+ */
15
+ export interface ErrorEvent extends PDFViewerEvent {
16
+ /**
17
+ * The raised error.
18
+ */
19
+ error: Error | {
20
+ message: string;
21
+ };
22
+ }
23
+ /**
24
+ * The KendoReact [PDFViewer]({% slug api_pdf-viewer_pdfviewer %}) DownloadEvent object.
25
+ */
26
+ export interface DownloadEvent extends PDFViewerEvent {
27
+ /**
28
+ * The Blob object.
29
+ */
30
+ blob: Blob;
31
+ /**
32
+ * The name which will be used for saving the file.
33
+ */
34
+ fileName: string;
35
+ /**
36
+ * The options which will be used for saving the file.
37
+ */
38
+ saveOptions: SaveOptions;
39
+ }
40
+ /**
41
+ * The KendoReact [PDFViewer]({% slug api_pdf-viewer_pdfviewer %}) LoadEvent object.
42
+ */
43
+ export interface LoadEvent extends PDFViewerEvent {
44
+ }
45
+ /**
46
+ * The props of the KendoReact [PDFViewer]({% slug api_pdf-viewer_pdfviewer %}) component.
47
+ */
48
+ export interface PDFViewerProps {
49
+ /**
50
+ * Represents the url of the PDF file.
51
+ */
52
+ url?: string;
53
+ /**
54
+ * Represents the data of the PDF file in Base64 format.
55
+ */
56
+ data?: string;
57
+ /**
58
+ * Represents the raw binary data buffer of the PDF file.
59
+ */
60
+ arrayBuffer?: ArrayBuffer;
61
+ /**
62
+ * Represents the data of the PDF file in typed array format.
63
+ */
64
+ typedArray?: TypedArray;
65
+ /**
66
+ * Represents the additional styles which will be added to the PDFViewer component.
67
+ */
68
+ style?: React.CSSProperties;
69
+ /**
70
+ * Represents the file name used to save the file when the user clicks the download tool.
71
+ */
72
+ saveFileName?: string;
73
+ /**
74
+ * Represents the options for saving the file when the user clicks the download tool.
75
+ */
76
+ saveOptions?: SaveOptions;
77
+ /**
78
+ * Represents the zoom levels populated in the ComboBox component.
79
+ */
80
+ zoomLevels?: {
81
+ id: number;
82
+ value: number;
83
+ text: string;
84
+ type: string;
85
+ locationString?: string;
86
+ }[];
87
+ /**
88
+ * Fires when an error occurs.
89
+ */
90
+ onError?: (event: ErrorEvent) => void;
91
+ /**
92
+ * Fires when a PDF document has been loaded.
93
+ */
94
+ onLoad?: (event: LoadEvent) => void;
95
+ /**
96
+ * Fires when the download tool has been clicked. To prevent the download, return `false`.
97
+ */
98
+ onDownload?: (event: DownloadEvent) => boolean;
99
+ /**
100
+ * Fires when the toolbar component is about to be rendered. Use it to override the default appearance of the toolbar.
101
+ */
102
+ onRenderToolbar?: (defaultRendering: React.ReactElement<Toolbar>) => React.ReactNode;
103
+ /**
104
+ * Fires when the content component is about to be rendered. Use it to override the default appearance of the content.
105
+ */
106
+ onRenderContent?: (defaultRendering: React.ReactElement<HTMLDivElement>) => React.ReactNode;
107
+ /**
108
+ * Fires when the loading indication component is about to be rendered. Use it to override the default appearance of the loading.
109
+ */
110
+ onRenderLoader?: (defaultRendering: React.ReactElement<HTMLDivElement> | null) => React.ReactNode;
111
+ }
112
+ /**
113
+ * Represents the object which is passed to the [`ref`](https://reactjs.org/docs/refs-and-the-dom.html)
114
+ * callback of the [PDFViewer]({% slug api_pdf-viewer_pdfviewer %}) component.
115
+ */
116
+ export interface PDFViewerHandle {
117
+ /**
118
+ * The root DOM element of the PDFViewer component.
119
+ */
120
+ element: HTMLDivElement | null;
121
+ /**
122
+ * The props of the PDFViewer component.
123
+ */
124
+ props: PDFViewerProps;
125
+ /**
126
+ * The `PDF.js` document loaded in the PDFViewer component.
127
+ */
128
+ document: any;
129
+ /**
130
+ * The `PDF.js` pages loaded in the PDFViewer component.
131
+ */
132
+ pages: any[];
133
+ }
134
+ /**
135
+ * Represents the [KendoReact PDFViewer component]({% slug api_pdf-viewer_pdfviewerprops %}).
136
+ */
137
+ export declare const PDFViewer: React.ForwardRefExoticComponent<PDFViewerProps & React.RefAttributes<PDFViewerHandle | null>>;
138
+ export {};