react-native-pdf-jsi 4.1.1 → 4.1.2
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/PinchZoomView.js +85 -110
- package/ios/RNPDFPdf/RNPDFPdfView.mm +70 -12
- package/package.json +1 -1
package/PinchZoomView.js
CHANGED
|
@@ -6,120 +6,95 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
import React, {Component} from
|
|
11
|
-
import PropTypes from
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
StyleSheet,
|
|
15
|
-
PanResponder
|
|
16
|
-
} from 'react-native';
|
|
17
|
-
import {ViewPropTypes} from 'deprecated-react-native-prop-types';
|
|
9
|
+
"use strict";
|
|
10
|
+
import React, { Component } from "react";
|
|
11
|
+
import PropTypes from "prop-types";
|
|
12
|
+
import { View, StyleSheet, PanResponder } from "react-native";
|
|
13
|
+
import { ViewPropTypes } from "deprecated-react-native-prop-types";
|
|
18
14
|
export default class PinchZoomView extends Component {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
15
|
+
static propTypes = {
|
|
16
|
+
...ViewPropTypes,
|
|
17
|
+
scalable: PropTypes.bool,
|
|
18
|
+
onScaleChanged: PropTypes.func,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
static defaultProps = {
|
|
22
|
+
scalable: true,
|
|
23
|
+
onScaleChanged: (scale) => {},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
constructor(props) {
|
|
27
|
+
super(props);
|
|
28
|
+
this.state = {};
|
|
29
|
+
this.distant = 0;
|
|
30
|
+
this.gestureHandlers = PanResponder.create({
|
|
31
|
+
onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
|
|
32
|
+
onMoveShouldSetResponderCapture: (evt, gestureState) => {
|
|
33
|
+
return this.props.scalable && (evt.nativeEvent.touches.length >= 2 || gestureState.numberActiveTouches >= 2);
|
|
34
|
+
},
|
|
35
|
+
onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
|
|
36
|
+
onPanResponderGrant: this._handlePanResponderGrant,
|
|
37
|
+
onPanResponderMove: this._handlePanResponderMove,
|
|
38
|
+
onPanResponderRelease: this._handlePanResponderEnd,
|
|
39
|
+
onPanResponderTerminationRequest: (evt) => false,
|
|
40
|
+
onPanResponderTerminate: this._handlePanResponderTerminate,
|
|
41
|
+
onShouldBlockNativeResponder: (evt) => true,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_handleStartShouldSetPanResponder = (e, gestureState) => {
|
|
46
|
+
// don't respond to single touch to avoid shielding click on child components
|
|
47
|
+
return false;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
_handleMoveShouldSetPanResponder = (e, gestureState) => {
|
|
51
|
+
return this.props.scalable && (e.nativeEvent.touches.length >= 2 || gestureState.numberActiveTouches >= 2);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
_handlePanResponderGrant = (e, gestureState) => {
|
|
55
|
+
if (e.nativeEvent.touches.length >= 2 || gestureState.numberActiveTouches >= 2) {
|
|
56
|
+
let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX);
|
|
57
|
+
let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY);
|
|
58
|
+
this.distant = Math.sqrt(dx * dx + dy * dy);
|
|
49
59
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
_handlePanResponderEnd = (e, gestureState) => {
|
|
75
|
-
|
|
76
|
-
this.distant = 0;
|
|
77
|
-
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
_handlePanResponderTerminate = (e, gestureState) => {
|
|
81
|
-
|
|
82
|
-
this.distant = 0;
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
_handlePanResponderMove = (e, gestureState) => {
|
|
87
|
-
|
|
88
|
-
if ((e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2) && this.distant > 100) {
|
|
89
|
-
|
|
90
|
-
let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX);
|
|
91
|
-
let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY);
|
|
92
|
-
let distant = Math.sqrt(dx * dx + dy * dy);
|
|
93
|
-
let scale = (distant / this.distant);
|
|
94
|
-
let pageX = (e.nativeEvent.touches[0].pageX + e.nativeEvent.touches[1].pageX) / 2;
|
|
95
|
-
let pageY = (e.nativeEvent.touches[0].pageY + e.nativeEvent.touches[1].pageY) / 2;
|
|
96
|
-
let pinchInfo = {scale: scale, pageX: pageX, pageY: pageY};
|
|
97
|
-
|
|
98
|
-
this.props.onScaleChanged(pinchInfo);
|
|
99
|
-
this.distant = distant;
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
render() {
|
|
106
|
-
|
|
107
|
-
return (
|
|
108
|
-
<View
|
|
109
|
-
{...this.props}
|
|
110
|
-
{...this.gestureHandlers?.panHandlers}
|
|
111
|
-
style={[styles.container, this.props.style]}>
|
|
112
|
-
{this.props.children}
|
|
113
|
-
</View>
|
|
114
|
-
);
|
|
115
|
-
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
_handlePanResponderEnd = (e, gestureState) => {
|
|
63
|
+
this.distant = 0;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
_handlePanResponderTerminate = (e, gestureState) => {
|
|
67
|
+
this.distant = 0;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
_handlePanResponderMove = (e, gestureState) => {
|
|
71
|
+
if ((e.nativeEvent.touches.length >= 2 || gestureState.numberActiveTouches >= 2) && this.distant > 100) {
|
|
72
|
+
let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX);
|
|
73
|
+
let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY);
|
|
74
|
+
let distant = Math.sqrt(dx * dx + dy * dy);
|
|
75
|
+
let scale = distant / this.distant;
|
|
76
|
+
let pageX = (e.nativeEvent.touches[0].pageX + e.nativeEvent.touches[1].pageX) / 2;
|
|
77
|
+
let pageY = (e.nativeEvent.touches[0].pageY + e.nativeEvent.touches[1].pageY) / 2;
|
|
78
|
+
let pinchInfo = { scale: scale, pageX: pageX, pageY: pageY };
|
|
79
|
+
|
|
80
|
+
this.props.onScaleChanged(pinchInfo);
|
|
81
|
+
this.distant = distant;
|
|
116
82
|
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
render() {
|
|
86
|
+
return (
|
|
87
|
+
<View {...this.props} {...this.gestureHandlers?.panHandlers} style={[styles.container, this.props.style]}>
|
|
88
|
+
{this.props.children}
|
|
89
|
+
</View>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
117
92
|
}
|
|
118
93
|
|
|
119
94
|
const styles = StyleSheet.create({
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
95
|
+
container: {
|
|
96
|
+
flex: 1,
|
|
97
|
+
justifyContent: "center",
|
|
98
|
+
alignItems: "center",
|
|
99
|
+
},
|
|
125
100
|
});
|
|
@@ -54,6 +54,58 @@
|
|
|
54
54
|
const float MAX_SCALE = 3.0f;
|
|
55
55
|
const float MIN_SCALE = 1.0f;
|
|
56
56
|
|
|
57
|
+
|
|
58
|
+
@interface RNPDFScrollViewDelegateProxy : NSObject <UIScrollViewDelegate>
|
|
59
|
+
- (instancetype)initWithPrimary:(id<UIScrollViewDelegate>)primary secondary:(id<UIScrollViewDelegate>)secondary;
|
|
60
|
+
@end
|
|
61
|
+
|
|
62
|
+
@implementation RNPDFScrollViewDelegateProxy {
|
|
63
|
+
__weak id<UIScrollViewDelegate> _primary;
|
|
64
|
+
__weak id<UIScrollViewDelegate> _secondary;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (instancetype)initWithPrimary:(id<UIScrollViewDelegate>)primary secondary:(id<UIScrollViewDelegate>)secondary {
|
|
68
|
+
if (self = [super init]) {
|
|
69
|
+
_primary = primary;
|
|
70
|
+
_secondary = secondary;
|
|
71
|
+
}
|
|
72
|
+
return self;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
- (BOOL)respondsToSelector:(SEL)aSelector {
|
|
76
|
+
return [super respondsToSelector:aSelector]
|
|
77
|
+
|| (_primary && [_primary respondsToSelector:aSelector])
|
|
78
|
+
|| (_secondary && [_secondary respondsToSelector:aSelector]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (id)forwardingTargetForSelector:(SEL)aSelector {
|
|
82
|
+
if (_primary && [_primary respondsToSelector:aSelector]) {
|
|
83
|
+
return _primary;
|
|
84
|
+
}
|
|
85
|
+
if (_secondary && [_secondary respondsToSelector:aSelector]) {
|
|
86
|
+
return _secondary;
|
|
87
|
+
}
|
|
88
|
+
return [super forwardingTargetForSelector:aSelector];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
|
92
|
+
if (_primary && [_primary respondsToSelector:@selector(scrollViewDidScroll:)]) {
|
|
93
|
+
[_primary scrollViewDidScroll:scrollView];
|
|
94
|
+
}
|
|
95
|
+
if (_secondary && [_secondary respondsToSelector:@selector(scrollViewDidScroll:)]) {
|
|
96
|
+
[_secondary scrollViewDidScroll:scrollView];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
|
|
101
|
+
if (_primary && [_primary respondsToSelector:@selector(viewForZoomingInScrollView:)]) {
|
|
102
|
+
return [_primary viewForZoomingInScrollView:scrollView];
|
|
103
|
+
}
|
|
104
|
+
return nil;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@end
|
|
108
|
+
|
|
57
109
|
@interface RNPDFPdfView() <PDFDocumentDelegate, PDFViewDelegate
|
|
58
110
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
59
111
|
, RCTRNPDFPdfViewViewProtocol
|
|
@@ -68,6 +120,7 @@ const float MIN_SCALE = 1.0f;
|
|
|
68
120
|
PDFView *_pdfView;
|
|
69
121
|
UIScrollView *_internalScrollView;
|
|
70
122
|
id<UIScrollViewDelegate> _originalScrollDelegate;
|
|
123
|
+
RNPDFScrollViewDelegateProxy *_scrollDelegateProxy;
|
|
71
124
|
PDFOutline *root;
|
|
72
125
|
float _fixScaleFactor;
|
|
73
126
|
bool _initialed;
|
|
@@ -559,10 +612,15 @@ using namespace facebook::react;
|
|
|
559
612
|
if (_pdfDocument && ([changedProps containsObject:@"path"] ||
|
|
560
613
|
[changedProps containsObject:@"scrollEnabled"])) {
|
|
561
614
|
// If path changed, restore original delegate before reconfiguring
|
|
562
|
-
if ([changedProps containsObject:@"path"] && _internalScrollView
|
|
563
|
-
|
|
615
|
+
if ([changedProps containsObject:@"path"] && _internalScrollView) {
|
|
616
|
+
if (_originalScrollDelegate) {
|
|
617
|
+
_internalScrollView.delegate = _originalScrollDelegate;
|
|
618
|
+
} else {
|
|
619
|
+
_internalScrollView.delegate = nil;
|
|
620
|
+
}
|
|
564
621
|
_internalScrollView = nil;
|
|
565
622
|
_originalScrollDelegate = nil;
|
|
623
|
+
_scrollDelegateProxy = nil;
|
|
566
624
|
}
|
|
567
625
|
|
|
568
626
|
// Use dispatch_async to ensure view hierarchy is fully set up after document load
|
|
@@ -1021,16 +1079,20 @@ using namespace facebook::react;
|
|
|
1021
1079
|
scrollView.alwaysBounceHorizontal = NO;
|
|
1022
1080
|
// Keep vertical bounce enabled for natural scrolling feel
|
|
1023
1081
|
scrollView.bounces = YES;
|
|
1024
|
-
|
|
1025
|
-
//
|
|
1026
|
-
//
|
|
1082
|
+
|
|
1083
|
+
// IMPORTANT: PDFKit relies on the scrollView delegate for pinch-zoom (viewForZoomingInScrollView).
|
|
1084
|
+
// Install a proxy delegate that forwards to the original delegate, while still letting us observe scroll events.
|
|
1027
1085
|
if (!_internalScrollView) {
|
|
1028
1086
|
_internalScrollView = scrollView;
|
|
1029
|
-
// Store original delegate if it exists and is not us
|
|
1030
1087
|
if (scrollView.delegate && scrollView.delegate != self) {
|
|
1031
1088
|
_originalScrollDelegate = scrollView.delegate;
|
|
1032
1089
|
}
|
|
1033
|
-
|
|
1090
|
+
if (_originalScrollDelegate) {
|
|
1091
|
+
_scrollDelegateProxy = [[RNPDFScrollViewDelegateProxy alloc] initWithPrimary:_originalScrollDelegate secondary:(id<UIScrollViewDelegate>)self];
|
|
1092
|
+
scrollView.delegate = (id<UIScrollViewDelegate>)_scrollDelegateProxy;
|
|
1093
|
+
} else {
|
|
1094
|
+
scrollView.delegate = self;
|
|
1095
|
+
}
|
|
1034
1096
|
}
|
|
1035
1097
|
}
|
|
1036
1098
|
|
|
@@ -1042,11 +1104,7 @@ using namespace facebook::react;
|
|
|
1042
1104
|
#pragma mark - UIScrollViewDelegate
|
|
1043
1105
|
|
|
1044
1106
|
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
|
1045
|
-
|
|
1046
|
-
if (_originalScrollDelegate && [_originalScrollDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
|
|
1047
|
-
[_originalScrollDelegate scrollViewDidScroll:scrollView];
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1107
|
+
|
|
1050
1108
|
if (!_pdfDocument || _singlePage) {
|
|
1051
1109
|
return;
|
|
1052
1110
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-pdf-jsi",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.2",
|
|
4
4
|
"summary": "High-performance React Native PDF viewer with JSI acceleration - up to 80x faster than traditional bridge",
|
|
5
5
|
"description": "🚀 Ultra-fast React Native PDF viewer with JSI (JavaScript Interface) integration for maximum performance. Features lazy loading, smart caching, progressive loading, and zero-bridge overhead operations. Perfect for large PDF files with 30-day persistent cache and advanced memory optimization. Google Play 16KB page size compliant for Android 15+. Supports iOS, Android, and Windows platforms.",
|
|
6
6
|
"main": "index.js",
|