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 CHANGED
@@ -6,120 +6,95 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
 
9
- 'use strict';
10
- import React, {Component} from 'react';
11
- import PropTypes from 'prop-types';
12
- import {
13
- View,
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
- static propTypes = {
21
- ...ViewPropTypes,
22
- scalable: PropTypes.bool,
23
- onScaleChanged: PropTypes.func,
24
- };
25
-
26
- static defaultProps = {
27
- scalable: true,
28
- onScaleChanged: (scale) => {
29
- },
30
- };
31
-
32
- constructor(props) {
33
-
34
- super(props);
35
- this.state = {};
36
- this.distant = 0;
37
- this.gestureHandlers = PanResponder.create({
38
- onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
39
- onMoveShouldSetResponderCapture: (evt, gestureState) => (true),
40
- onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
41
- onPanResponderGrant: this._handlePanResponderGrant,
42
- onPanResponderMove: this._handlePanResponderMove,
43
- onPanResponderRelease: this._handlePanResponderEnd,
44
- onPanResponderTerminationRequest: evt => false,
45
- onPanResponderTerminate: this._handlePanResponderTerminate,
46
- onShouldBlockNativeResponder: evt => true
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
- _handleStartShouldSetPanResponder = (e, gestureState) => {
52
-
53
- // don't respond to single touch to avoid shielding click on child components
54
- return false;
55
-
56
- };
57
-
58
- _handleMoveShouldSetPanResponder = (e, gestureState) => {
59
-
60
- return this.props.scalable && (e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2);
61
-
62
- };
63
-
64
- _handlePanResponderGrant = (e, gestureState) => {
65
-
66
- if (e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2) {
67
- let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX);
68
- let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY);
69
- this.distant = Math.sqrt(dx * dx + dy * dy);
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
- container: {
121
- flex: 1,
122
- justifyContent: 'center',
123
- alignItems: 'center'
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 && _originalScrollDelegate) {
563
- _internalScrollView.delegate = _originalScrollDelegate;
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
- // Set delegate for scroll tracking (only once to avoid conflicts)
1026
- // Store original delegate before replacing it to preserve PDFView's internal scrolling
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
- scrollView.delegate = self;
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
- // Forward to original delegate first if it exists (important for PDFView's scrolling)
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.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",