@amafil/react-native-pdf-toolkit 1.0.15 → 1.1.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/README.md +57 -0
- package/android/src/main/java/org/wonday/pdf/PdfManager.java +56 -0
- package/android/src/main/java/org/wonday/pdf/PdfView.java +1192 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNPDFPdfViewManagerDelegate.java +30 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNPDFPdfViewManagerInterface.java +10 -0
- package/annotationDocumentUtils.js +74 -0
- package/fabric/RNPDFPdfNativeComponent.js +17 -1
- package/index.d.ts +102 -1
- package/index.js +110 -0
- package/index.js.flow +72 -0
- package/ios/RNPDFPdf/RNPDFPdfView.h +11 -0
- package/ios/RNPDFPdf/RNPDFPdfView.mm +1242 -0
- package/ios/RNPDFPdf/RNPDFPdfViewManager.mm +37 -0
- package/package.json +2 -1
package/android/src/paper/java/com/facebook/react/viewmanagers/RNPDFPdfViewManagerDelegate.java
CHANGED
|
@@ -62,6 +62,27 @@ public class RNPDFPdfViewManagerDelegate<T extends View, U extends BaseViewManag
|
|
|
62
62
|
case "enableDoubleTapZoom":
|
|
63
63
|
mViewManager.setEnableDoubleTapZoom(view, value == null ? false : (boolean) value);
|
|
64
64
|
break;
|
|
65
|
+
case "annotations":
|
|
66
|
+
mViewManager.setAnnotations(view, value == null ? null : (String) value);
|
|
67
|
+
break;
|
|
68
|
+
case "annotationMode":
|
|
69
|
+
mViewManager.setAnnotationMode(view, value == null ? false : (boolean) value);
|
|
70
|
+
break;
|
|
71
|
+
case "annotationTool":
|
|
72
|
+
mViewManager.setAnnotationTool(view, value == null ? null : (String) value);
|
|
73
|
+
break;
|
|
74
|
+
case "annotationEditable":
|
|
75
|
+
mViewManager.setAnnotationEditable(view, value == null ? false : (boolean) value);
|
|
76
|
+
break;
|
|
77
|
+
case "annotationIdMode":
|
|
78
|
+
mViewManager.setAnnotationIdMode(view, value == null ? null : (String) value);
|
|
79
|
+
break;
|
|
80
|
+
case "annotationInkColor":
|
|
81
|
+
mViewManager.setAnnotationInkColor(view, value == null ? null : (String) value);
|
|
82
|
+
break;
|
|
83
|
+
case "annotationInkThickness":
|
|
84
|
+
mViewManager.setAnnotationInkThickness(view, value == null ? 0f : ((Double) value).floatValue());
|
|
85
|
+
break;
|
|
65
86
|
case "enableAntialiasing":
|
|
66
87
|
mViewManager.setEnableAntialiasing(view, value == null ? false : (boolean) value);
|
|
67
88
|
break;
|
|
@@ -87,6 +108,15 @@ public class RNPDFPdfViewManagerDelegate<T extends View, U extends BaseViewManag
|
|
|
87
108
|
case "setNativePage":
|
|
88
109
|
mViewManager.setNativePage(view, args.getInt(0));
|
|
89
110
|
break;
|
|
111
|
+
case "saveAnnotations":
|
|
112
|
+
mViewManager.saveAnnotations(view);
|
|
113
|
+
break;
|
|
114
|
+
case "deleteSelectedAnnotation":
|
|
115
|
+
mViewManager.deleteSelectedAnnotation(view);
|
|
116
|
+
break;
|
|
117
|
+
case "deleteAllAnnotations":
|
|
118
|
+
mViewManager.deleteAllAnnotations(view);
|
|
119
|
+
break;
|
|
90
120
|
}
|
|
91
121
|
}
|
|
92
122
|
}
|
package/android/src/paper/java/com/facebook/react/viewmanagers/RNPDFPdfViewManagerInterface.java
CHANGED
|
@@ -26,10 +26,20 @@ public interface RNPDFPdfViewManagerInterface<T extends View> {
|
|
|
26
26
|
void setEnableRTL(T view, boolean value);
|
|
27
27
|
void setEnableAnnotationRendering(T view, boolean value);
|
|
28
28
|
void setEnableDoubleTapZoom(T view, boolean value);
|
|
29
|
+
void setAnnotations(T view, @Nullable String value);
|
|
30
|
+
void setAnnotationMode(T view, boolean value);
|
|
31
|
+
void setAnnotationTool(T view, @Nullable String value);
|
|
32
|
+
void setAnnotationEditable(T view, boolean value);
|
|
33
|
+
void setAnnotationIdMode(T view, @Nullable String value);
|
|
34
|
+
void setAnnotationInkColor(T view, @Nullable String value);
|
|
35
|
+
void setAnnotationInkThickness(T view, float value);
|
|
29
36
|
void setEnableAntialiasing(T view, boolean value);
|
|
30
37
|
void setFitPolicy(T view, int value);
|
|
31
38
|
void setSpacing(T view, int value);
|
|
32
39
|
void setPassword(T view, @Nullable String value);
|
|
33
40
|
void setSinglePage(T view, boolean value);
|
|
34
41
|
void setNativePage(T view, int page);
|
|
42
|
+
void saveAnnotations(T view);
|
|
43
|
+
void deleteSelectedAnnotation(T view);
|
|
44
|
+
void deleteAllAnnotations(T view);
|
|
35
45
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const LEGACY_MARKUP_TYPES = new Set(['underline', 'strikeout']);
|
|
4
|
+
|
|
5
|
+
export function normalizeAnnotation(annotation) {
|
|
6
|
+
if (!annotation || typeof annotation !== 'object' || Array.isArray(annotation)) {
|
|
7
|
+
return annotation;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (!LEGACY_MARKUP_TYPES.has(annotation.type)) {
|
|
11
|
+
return annotation;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
...annotation,
|
|
16
|
+
type: 'highlight',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function normalizeAnnotationPayload(payload) {
|
|
21
|
+
if (!payload || typeof payload !== 'object') {
|
|
22
|
+
return payload;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (Array.isArray(payload)) {
|
|
26
|
+
return payload.map(normalizeAnnotation);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!Array.isArray(payload.annotations)) {
|
|
30
|
+
return payload;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
...payload,
|
|
35
|
+
annotations: payload.annotations.map(normalizeAnnotation),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function joinAnnotationMessagePayload(messageParts, startIndex = 1) {
|
|
40
|
+
if (!Array.isArray(messageParts) || messageParts.length <= startIndex) {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return messageParts.slice(startIndex).join('|');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function parseAnnotationMessagePayload(messageParts, startIndex = 1) {
|
|
48
|
+
const payload = joinAnnotationMessagePayload(messageParts, startIndex);
|
|
49
|
+
|
|
50
|
+
if (!payload) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
return normalizeAnnotationPayload(JSON.parse(payload));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return payload;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function stringifyAnnotationDocument(document, onError) {
|
|
62
|
+
if (!document) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
return JSON.stringify(normalizeAnnotationPayload(document));
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (onError) {
|
|
70
|
+
onError(error);
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -30,6 +30,13 @@
|
|
|
30
30
|
fitPolicy: ?Int32,
|
|
31
31
|
spacing: ?Int32,
|
|
32
32
|
password: ?string,
|
|
33
|
+
annotations: ?string,
|
|
34
|
+
annotationMode: ?boolean,
|
|
35
|
+
annotationTool: ?string,
|
|
36
|
+
annotationEditable: ?boolean,
|
|
37
|
+
annotationIdMode: ?string,
|
|
38
|
+
annotationInkColor: ?string,
|
|
39
|
+
annotationInkThickness: ?Float,
|
|
33
40
|
onChange: ?BubblingEventHandler<ChangeEvent>,
|
|
34
41
|
singlePage: ?boolean,
|
|
35
42
|
|}>;
|
|
@@ -47,10 +54,19 @@
|
|
|
47
54
|
+stopNativeAutoScroll: (
|
|
48
55
|
viewRef: React.ElementRef<ComponentType>,
|
|
49
56
|
) => void;
|
|
57
|
+
+saveAnnotations: (
|
|
58
|
+
viewRef: React.ElementRef<ComponentType>,
|
|
59
|
+
) => void;
|
|
60
|
+
+deleteSelectedAnnotation: (
|
|
61
|
+
viewRef: React.ElementRef<ComponentType>,
|
|
62
|
+
) => void;
|
|
63
|
+
+deleteAllAnnotations: (
|
|
64
|
+
viewRef: React.ElementRef<ComponentType>,
|
|
65
|
+
) => void;
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
|
|
53
|
-
supportedCommands: ['setNativePage', 'startNativeAutoScroll', 'stopNativeAutoScroll'],
|
|
69
|
+
supportedCommands: ['setNativePage', 'startNativeAutoScroll', 'stopNativeAutoScroll', 'saveAnnotations', 'deleteSelectedAnnotation', 'deleteAllAnnotations'],
|
|
54
70
|
});
|
|
55
71
|
|
|
56
72
|
export default codegenNativeComponent<NativeProps>('RNPDFPdfView');
|
package/index.d.ts
CHANGED
|
@@ -27,6 +27,68 @@ export type Source = {
|
|
|
27
27
|
method?: string;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
export type AnnotationRotation = 0 | 90 | 180 | 270;
|
|
31
|
+
export type AnnotationIdMode = 'auto' | 'manual';
|
|
32
|
+
export type AnnotationTool = 'select' | 'ink' | 'text' | 'highlight';
|
|
33
|
+
export type AnnotationTextAlign = 'left' | 'center' | 'right';
|
|
34
|
+
|
|
35
|
+
export type AnnotationPoint = {
|
|
36
|
+
x: number,
|
|
37
|
+
y: number,
|
|
38
|
+
pressure?: number,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type AnnotationBounds = {
|
|
42
|
+
x: number,
|
|
43
|
+
y: number,
|
|
44
|
+
width: number,
|
|
45
|
+
height: number,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type AnnotationStyle = {
|
|
49
|
+
color?: string,
|
|
50
|
+
thickness?: number,
|
|
51
|
+
fontFamily?: string,
|
|
52
|
+
fontSize?: number,
|
|
53
|
+
textAlign?: AnnotationTextAlign,
|
|
54
|
+
rotation?: AnnotationRotation,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type AnnotationBase = {
|
|
58
|
+
id: string,
|
|
59
|
+
page: number,
|
|
60
|
+
locked?: boolean,
|
|
61
|
+
createdAt?: number,
|
|
62
|
+
updatedAt?: number,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type InkAnnotation = AnnotationBase & {
|
|
66
|
+
type: 'ink',
|
|
67
|
+
points: AnnotationPoint[],
|
|
68
|
+
style?: AnnotationStyle,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type TextAnnotation = AnnotationBase & {
|
|
72
|
+
type: 'text',
|
|
73
|
+
bounds: AnnotationBounds,
|
|
74
|
+
text: string,
|
|
75
|
+
style?: AnnotationStyle,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export type MarkupAnnotation = AnnotationBase & {
|
|
79
|
+
type: 'highlight',
|
|
80
|
+
bounds: AnnotationBounds,
|
|
81
|
+
style?: AnnotationStyle,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export type Annotation = InkAnnotation | TextAnnotation | MarkupAnnotation;
|
|
85
|
+
|
|
86
|
+
export type AnnotationDocument = {
|
|
87
|
+
editable?: boolean,
|
|
88
|
+
idMode?: AnnotationIdMode,
|
|
89
|
+
annotations: Annotation[],
|
|
90
|
+
};
|
|
91
|
+
|
|
30
92
|
export type TextSelectionChangeEvent = {
|
|
31
93
|
nativeEvent:
|
|
32
94
|
| {
|
|
@@ -58,6 +120,34 @@ export interface PdfProps {
|
|
|
58
120
|
enableRTL?: boolean,
|
|
59
121
|
enableAnnotationRendering?: boolean,
|
|
60
122
|
enableDoubleTapZoom?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Initial annotation document to render in the overlay.
|
|
125
|
+
*/
|
|
126
|
+
annotations?: AnnotationDocument,
|
|
127
|
+
/**
|
|
128
|
+
* Enable annotation editing mode.
|
|
129
|
+
*/
|
|
130
|
+
annotationMode?: boolean,
|
|
131
|
+
/**
|
|
132
|
+
* Active tool used while annotation editing is enabled.
|
|
133
|
+
*/
|
|
134
|
+
annotationTool?: AnnotationTool,
|
|
135
|
+
/**
|
|
136
|
+
* Allow in-place annotation edits.
|
|
137
|
+
*/
|
|
138
|
+
annotationEditable?: boolean,
|
|
139
|
+
/**
|
|
140
|
+
* Controls how annotation IDs are generated and preserved.
|
|
141
|
+
*/
|
|
142
|
+
annotationIdMode?: AnnotationIdMode,
|
|
143
|
+
/**
|
|
144
|
+
* Default color applied to newly created ink annotations.
|
|
145
|
+
*/
|
|
146
|
+
annotationInkColor?: string,
|
|
147
|
+
/**
|
|
148
|
+
* Default thickness applied to newly created ink annotations.
|
|
149
|
+
*/
|
|
150
|
+
annotationInkThickness?: number,
|
|
61
151
|
/**
|
|
62
152
|
* Only works on iOS. Defaults to `true`.
|
|
63
153
|
*/
|
|
@@ -80,11 +170,22 @@ export interface PdfProps {
|
|
|
80
170
|
onPressLink?: (url: string) => void,
|
|
81
171
|
onAutoScrollEnd?: () => void,
|
|
82
172
|
onTextSelectionChange?: (event: TextSelectionChangeEvent) => void,
|
|
83
|
-
onAutoScrollEnd?: () => void,
|
|
84
173
|
}
|
|
85
174
|
|
|
86
175
|
export interface PdfRef {
|
|
87
176
|
setPage(pageNumber: number): void
|
|
177
|
+
/**
|
|
178
|
+
* Resolves with the current annotation document serialized by native code.
|
|
179
|
+
*/
|
|
180
|
+
saveAnnotations(): Promise<AnnotationDocument>
|
|
181
|
+
/**
|
|
182
|
+
* Deletes the currently selected custom annotation.
|
|
183
|
+
*/
|
|
184
|
+
deleteSelectedAnnotation(): void
|
|
185
|
+
/**
|
|
186
|
+
* Deletes all custom annotations in the current overlay draft.
|
|
187
|
+
*/
|
|
188
|
+
deleteAllAnnotations(): void
|
|
88
189
|
/**
|
|
89
190
|
* Start smooth automatic vertical scrolling using the display refresh rate.
|
|
90
191
|
* @param dpPerSecond - Scroll speed in density-independent pixels (dp) per second (default: 15). Produces consistent physical speed across screen densities.
|
package/index.js
CHANGED
|
@@ -23,6 +23,11 @@ import PdfViewNativeComponent, {
|
|
|
23
23
|
import ReactNativeBlobUtil from 'react-native-blob-util'
|
|
24
24
|
import {ViewPropTypes} from 'deprecated-react-native-prop-types';
|
|
25
25
|
const SHA1 = require('crypto-js/sha1');
|
|
26
|
+
import {
|
|
27
|
+
joinAnnotationMessagePayload,
|
|
28
|
+
parseAnnotationMessagePayload,
|
|
29
|
+
stringifyAnnotationDocument,
|
|
30
|
+
} from './annotationDocumentUtils';
|
|
26
31
|
import PdfView from './PdfView';
|
|
27
32
|
|
|
28
33
|
export default class Pdf extends Component {
|
|
@@ -57,6 +62,13 @@ export default class Pdf extends Component {
|
|
|
57
62
|
fitPolicy: PropTypes.number,
|
|
58
63
|
trustAllCerts: PropTypes.bool,
|
|
59
64
|
singlePage: PropTypes.bool,
|
|
65
|
+
annotations: PropTypes.object,
|
|
66
|
+
annotationMode: PropTypes.bool,
|
|
67
|
+
annotationTool: PropTypes.oneOf(['select', 'ink', 'text', 'highlight']),
|
|
68
|
+
annotationEditable: PropTypes.bool,
|
|
69
|
+
annotationIdMode: PropTypes.oneOf(['auto', 'manual']),
|
|
70
|
+
annotationInkColor: PropTypes.string,
|
|
71
|
+
annotationInkThickness: PropTypes.number,
|
|
60
72
|
onLoadComplete: PropTypes.func,
|
|
61
73
|
onPageChanged: PropTypes.func,
|
|
62
74
|
onError: PropTypes.func,
|
|
@@ -96,6 +108,13 @@ export default class Pdf extends Component {
|
|
|
96
108
|
trustAllCerts: true,
|
|
97
109
|
usePDFKit: true,
|
|
98
110
|
singlePage: false,
|
|
111
|
+
annotations: null,
|
|
112
|
+
annotationMode: false,
|
|
113
|
+
annotationTool: 'select',
|
|
114
|
+
annotationEditable: true,
|
|
115
|
+
annotationIdMode: 'auto',
|
|
116
|
+
annotationInkColor: '#111111',
|
|
117
|
+
annotationInkThickness: 2,
|
|
99
118
|
onLoadProgress: (percent) => {
|
|
100
119
|
},
|
|
101
120
|
onLoadComplete: (numberOfPages, path) => {
|
|
@@ -127,6 +146,7 @@ export default class Pdf extends Component {
|
|
|
127
146
|
};
|
|
128
147
|
|
|
129
148
|
this.lastRNBFTask = null;
|
|
149
|
+
this._annotationSavePromise = null;
|
|
130
150
|
|
|
131
151
|
}
|
|
132
152
|
|
|
@@ -156,6 +176,10 @@ export default class Pdf extends Component {
|
|
|
156
176
|
componentWillUnmount() {
|
|
157
177
|
this._mounted = false;
|
|
158
178
|
this.stopAutoScroll();
|
|
179
|
+
if (this._annotationSavePromise) {
|
|
180
|
+
this._annotationSavePromise.reject(new Error('Pdf unmounted before annotation save completed'));
|
|
181
|
+
this._annotationSavePromise = null;
|
|
182
|
+
}
|
|
159
183
|
if (this.lastRNBFTask) {
|
|
160
184
|
// this.lastRNBFTask.cancel(err => {
|
|
161
185
|
// });
|
|
@@ -372,6 +396,70 @@ export default class Pdf extends Component {
|
|
|
372
396
|
|
|
373
397
|
}
|
|
374
398
|
|
|
399
|
+
saveAnnotations() {
|
|
400
|
+
if (this._annotationSavePromise) {
|
|
401
|
+
return Promise.reject(new Error('An annotation save is already in progress'));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return new Promise((resolve, reject) => {
|
|
405
|
+
if (!this._root) {
|
|
406
|
+
reject(new Error('Pdf is not mounted'));
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
this._annotationSavePromise = {resolve, reject};
|
|
411
|
+
|
|
412
|
+
if (!!global?.nativeFabricUIManager) {
|
|
413
|
+
if (PdfViewCommands.saveAnnotations) {
|
|
414
|
+
PdfViewCommands.saveAnnotations(this._root);
|
|
415
|
+
} else {
|
|
416
|
+
this._annotationSavePromise = null;
|
|
417
|
+
reject(new Error('Annotation save command is not available'));
|
|
418
|
+
}
|
|
419
|
+
} else {
|
|
420
|
+
const ReactNative = require('react-native');
|
|
421
|
+
try {
|
|
422
|
+
ReactNative.UIManager.dispatchViewManagerCommand(
|
|
423
|
+
ReactNative.findNodeHandle(this._root),
|
|
424
|
+
'saveAnnotations',
|
|
425
|
+
[],
|
|
426
|
+
);
|
|
427
|
+
} catch (error) {
|
|
428
|
+
this._annotationSavePromise = null;
|
|
429
|
+
reject(error);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
deleteSelectedAnnotation() {
|
|
436
|
+
this._dispatchAnnotationCommand('deleteSelectedAnnotation', PdfViewCommands.deleteSelectedAnnotation);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
deleteAllAnnotations() {
|
|
440
|
+
this._dispatchAnnotationCommand('deleteAllAnnotations', PdfViewCommands.deleteAllAnnotations);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
_dispatchAnnotationCommand(commandName, fabricCommand) {
|
|
444
|
+
if (!this._root) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (!!global?.nativeFabricUIManager) {
|
|
449
|
+
if (fabricCommand) {
|
|
450
|
+
fabricCommand(this._root);
|
|
451
|
+
}
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const ReactNative = require('react-native');
|
|
456
|
+
ReactNative.UIManager.dispatchViewManagerCommand(
|
|
457
|
+
ReactNative.findNodeHandle(this._root),
|
|
458
|
+
commandName,
|
|
459
|
+
[],
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
375
463
|
startAutoScroll( dpPerSecond = 15, resumeDelay = 3000 ) {
|
|
376
464
|
this._isAutoScrollActive = true;
|
|
377
465
|
if (!!global?.nativeFabricUIManager) {
|
|
@@ -465,6 +553,20 @@ export default class Pdf extends Component {
|
|
|
465
553
|
} else if (message[0] === 'autoScrollEnd') {
|
|
466
554
|
this._isAutoScrollActive = false;
|
|
467
555
|
this.props.onAutoScrollEnd && this.props.onAutoScrollEnd();
|
|
556
|
+
} else if (message[0] === 'annotationSaveComplete') {
|
|
557
|
+
const annotationDocument = parseAnnotationMessagePayload(message);
|
|
558
|
+
|
|
559
|
+
if (this._annotationSavePromise) {
|
|
560
|
+
this._annotationSavePromise.resolve(annotationDocument);
|
|
561
|
+
this._annotationSavePromise = null;
|
|
562
|
+
}
|
|
563
|
+
} else if (message[0] === 'annotationSaveError') {
|
|
564
|
+
const annotationError = joinAnnotationMessagePayload(message);
|
|
565
|
+
|
|
566
|
+
if (this._annotationSavePromise) {
|
|
567
|
+
this._annotationSavePromise.reject(new Error(annotationError || 'Annotation save failed'));
|
|
568
|
+
this._annotationSavePromise = null;
|
|
569
|
+
}
|
|
468
570
|
}
|
|
469
571
|
}
|
|
470
572
|
|
|
@@ -476,7 +578,13 @@ export default class Pdf extends Component {
|
|
|
476
578
|
|
|
477
579
|
};
|
|
478
580
|
|
|
581
|
+
_getNativeAnnotations = () => {
|
|
582
|
+
return stringifyAnnotationDocument(this.props.annotations, this._onError);
|
|
583
|
+
};
|
|
584
|
+
|
|
479
585
|
render() {
|
|
586
|
+
const nativeAnnotations = this._getNativeAnnotations();
|
|
587
|
+
|
|
480
588
|
if (Platform.OS === "android" || Platform.OS === "ios" || Platform.OS === "windows") {
|
|
481
589
|
return (
|
|
482
590
|
<View style={[this.props.style,{overflow: 'hidden'}]}>
|
|
@@ -492,6 +600,7 @@ export default class Pdf extends Component {
|
|
|
492
600
|
<PdfCustom
|
|
493
601
|
ref={component => (this._root = component)}
|
|
494
602
|
{...this.props}
|
|
603
|
+
annotations={nativeAnnotations}
|
|
495
604
|
style={[{flex:1,backgroundColor: '#EEE'}, this.props.style]}
|
|
496
605
|
path={this.state.path}
|
|
497
606
|
onChange={this._onChange}
|
|
@@ -501,6 +610,7 @@ export default class Pdf extends Component {
|
|
|
501
610
|
<PdfCustom
|
|
502
611
|
ref={component => (this._root = component)}
|
|
503
612
|
{...this.props}
|
|
613
|
+
annotations={nativeAnnotations}
|
|
504
614
|
style={[{backgroundColor: '#EEE',overflow: 'hidden'}, this.props.style]}
|
|
505
615
|
path={this.state.path}
|
|
506
616
|
onChange={this._onChange}
|
package/index.js.flow
CHANGED
|
@@ -24,6 +24,68 @@ export type Source = {
|
|
|
24
24
|
uri: string
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
export type AnnotationRotation = 0 | 90 | 180 | 270;
|
|
28
|
+
export type AnnotationIdMode = 'auto' | 'manual';
|
|
29
|
+
export type AnnotationTool = 'select' | 'ink' | 'text' | 'highlight';
|
|
30
|
+
export type AnnotationTextAlign = 'left' | 'center' | 'right';
|
|
31
|
+
|
|
32
|
+
export type AnnotationPoint = {
|
|
33
|
+
x: number,
|
|
34
|
+
y: number,
|
|
35
|
+
pressure?: number,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type AnnotationBounds = {
|
|
39
|
+
x: number,
|
|
40
|
+
y: number,
|
|
41
|
+
width: number,
|
|
42
|
+
height: number,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type AnnotationStyle = {
|
|
46
|
+
color?: string,
|
|
47
|
+
thickness?: number,
|
|
48
|
+
fontFamily?: string,
|
|
49
|
+
fontSize?: number,
|
|
50
|
+
textAlign?: AnnotationTextAlign,
|
|
51
|
+
rotation?: AnnotationRotation,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type AnnotationBase = {
|
|
55
|
+
id: string,
|
|
56
|
+
page: number,
|
|
57
|
+
locked?: boolean,
|
|
58
|
+
createdAt?: number,
|
|
59
|
+
updatedAt?: number,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type InkAnnotation = AnnotationBase & {
|
|
63
|
+
type: 'ink',
|
|
64
|
+
points: Array<AnnotationPoint>,
|
|
65
|
+
style?: AnnotationStyle,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type TextAnnotation = AnnotationBase & {
|
|
69
|
+
type: 'text',
|
|
70
|
+
bounds: AnnotationBounds,
|
|
71
|
+
text: string,
|
|
72
|
+
style?: AnnotationStyle,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export type MarkupAnnotation = AnnotationBase & {
|
|
76
|
+
type: 'highlight',
|
|
77
|
+
bounds: AnnotationBounds,
|
|
78
|
+
style?: AnnotationStyle,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export type Annotation = InkAnnotation | TextAnnotation | MarkupAnnotation;
|
|
82
|
+
|
|
83
|
+
export type AnnotationDocument = {
|
|
84
|
+
editable?: boolean,
|
|
85
|
+
idMode?: AnnotationIdMode,
|
|
86
|
+
annotations: Array<Annotation>,
|
|
87
|
+
};
|
|
88
|
+
|
|
27
89
|
export type TableContent = {
|
|
28
90
|
children: TableContent[],
|
|
29
91
|
mNativePtr: number,
|
|
@@ -33,6 +95,13 @@ export type TableContent = {
|
|
|
33
95
|
|
|
34
96
|
export type Props = {
|
|
35
97
|
renderActivityIndicator?: (progress: number) => Node,
|
|
98
|
+
annotations?: AnnotationDocument,
|
|
99
|
+
annotationMode?: boolean,
|
|
100
|
+
annotationTool?: AnnotationTool,
|
|
101
|
+
annotationEditable?: boolean,
|
|
102
|
+
annotationIdMode?: AnnotationIdMode,
|
|
103
|
+
annotationInkColor?: string,
|
|
104
|
+
annotationInkThickness?: number,
|
|
36
105
|
enableAnnotationRendering?: boolean,
|
|
37
106
|
enableAntialiasing?: boolean,
|
|
38
107
|
enablePaging?: boolean,
|
|
@@ -64,4 +133,7 @@ export type Props = {
|
|
|
64
133
|
|
|
65
134
|
declare export default class Pdf extends Component<Props> {
|
|
66
135
|
setPage: (pageNumber: number) => void;
|
|
136
|
+
saveAnnotations: () => Promise<AnnotationDocument>;
|
|
137
|
+
deleteSelectedAnnotation: () => void;
|
|
138
|
+
deleteAllAnnotations: () => void;
|
|
67
139
|
}
|
|
@@ -49,6 +49,13 @@ UIView
|
|
|
49
49
|
@property(nonatomic) BOOL enableRTL;
|
|
50
50
|
@property(nonatomic) BOOL enableAnnotationRendering;
|
|
51
51
|
@property(nonatomic) BOOL enableDoubleTapZoom;
|
|
52
|
+
@property(nonatomic, strong) NSString *annotations;
|
|
53
|
+
@property(nonatomic) BOOL annotationMode;
|
|
54
|
+
@property(nonatomic, strong) NSString *annotationTool;
|
|
55
|
+
@property(nonatomic) BOOL annotationEditable;
|
|
56
|
+
@property(nonatomic, strong) NSString *annotationIdMode;
|
|
57
|
+
@property(nonatomic, strong) NSString *annotationInkColor;
|
|
58
|
+
@property(nonatomic) float annotationInkThickness;
|
|
52
59
|
@property(nonatomic) int fitPolicy;
|
|
53
60
|
@property(nonatomic) int spacing;
|
|
54
61
|
@property(nonatomic, strong) NSString *password;
|
|
@@ -56,6 +63,10 @@ UIView
|
|
|
56
63
|
|
|
57
64
|
@property(nonatomic, copy) RCTBubblingEventBlock onChange;
|
|
58
65
|
|
|
66
|
+
- (void)saveAnnotations;
|
|
67
|
+
- (void)deleteSelectedAnnotation;
|
|
68
|
+
- (void)deleteAllAnnotations;
|
|
69
|
+
|
|
59
70
|
@property(nonatomic, strong) NSString *selectedText;
|
|
60
71
|
@property(nonatomic) BOOL enableTextSelection;
|
|
61
72
|
@property(nonatomic, strong) PDFSelection *currentPDFSelection;
|