@kishannareshpal/expo-pdf 0.1.0 → 0.2.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.
@@ -6,18 +6,18 @@ import expo.modules.kotlin.records.Record
6
6
 
7
7
  class ContentPadding: Record {
8
8
  @Field
9
- val left: Int = 0
9
+ val left: Float = 0f
10
10
 
11
11
  @Field
12
- val top: Int = 0
12
+ val top: Float = 0f
13
13
 
14
14
  @Field
15
- val right: Int = 0
15
+ val right: Float = 0f
16
16
 
17
17
  @Field
18
- val bottom: Int = 0
18
+ val bottom: Float = 0f
19
19
 
20
20
  fun toRect(): Rect {
21
- return Rect(this.left, this.top, this.right, this.bottom)
21
+ return Rect(this.left.toInt(), this.top.toInt(), this.right.toInt(), this.bottom.toInt())
22
22
  }
23
23
  }
@@ -9,11 +9,12 @@ type BaseProps = {
9
9
  uri: string;
10
10
  password?: string;
11
11
  pagingEnabled?: boolean;
12
- disableDoubleTapToZoom?: boolean;
12
+ doubleTapToZoom?: boolean;
13
13
  horizontal?: boolean;
14
14
  pageGap?: number;
15
15
  contentPadding?: ContentPadding;
16
16
  fitMode?: FitMode;
17
+ autoScale?: boolean;
17
18
  };
18
19
  export type PdfViewProps = BaseProps & {
19
20
  onLoadComplete?: (params: OnLoadCompleteEventPayload) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-view.d.ts","sourceRoot":"","sources":["../src/pdf-view.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAC9H,OAAO,EAAwB,SAAS,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAGtF,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAYD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG;IACrC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC9D,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,IAAI,CAAC;IAC5D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAChD,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,6DAMrB,YAAY,sBAiBd,CAAA"}
1
+ {"version":3,"file":"pdf-view.d.ts","sourceRoot":"","sources":["../src/pdf-view.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAC9H,OAAO,EAAwB,SAAS,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAGtF,KAAK,SAAS,GAAG;IACf,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAYD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG;IACrC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC9D,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,IAAI,CAAC;IAC5D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAChD,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,6DAMrB,YAAY,sBAkBd,CAAA"}
package/build/pdf-view.js CHANGED
@@ -4,7 +4,7 @@ import { StyleSheet } from 'react-native';
4
4
  import { forwardNativeEventTo } from './utils';
5
5
  const NativePdfView = requireNativeView('KJExpoPdf');
6
6
  export const PdfView = ({ style, onLoadComplete, onError, onPageChanged, ...props }) => {
7
- return (<NativePdfView style={[styles.container, style]} uri={props.uri} disableDoubleTapToZoom={props.disableDoubleTapToZoom} horizontal={props.horizontal} pageGap={props.pageGap} pagingEnabled={props.pagingEnabled} password={props.password} contentPadding={props.contentPadding} fitMode={props.fitMode} onLoadComplete={forwardNativeEventTo(onLoadComplete)} onPageChanged={forwardNativeEventTo(onPageChanged)} onError={forwardNativeEventTo(onError)}/>);
7
+ return (<NativePdfView style={[styles.container, style]} uri={props.uri} doubleTapToZoom={props.doubleTapToZoom} horizontal={props.horizontal} pageGap={props.pageGap} pagingEnabled={props.pagingEnabled} password={props.password} contentPadding={props.contentPadding} fitMode={props.fitMode} autoScale={props.autoScale} onLoadComplete={forwardNativeEventTo(onLoadComplete)} onPageChanged={forwardNativeEventTo(onPageChanged)} onError={forwardNativeEventTo(onError)}/>);
8
8
  };
9
9
  const styles = StyleSheet.create({
10
10
  container: {
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-view.js","sourceRoot":"","sources":["../src/pdf-view.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAmC,UAAU,EAAa,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAuB/C,MAAM,aAAa,GAA4C,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAU9F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,KAAK,EACL,cAAc,EACd,OAAO,EACP,aAAa,EACb,GAAG,KAAK,EACK,EAAE,EAAE;IACjB,OAAO,CACL,CAAC,aAAa,CACZ,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CACjC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CACf,sBAAsB,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC,CACrD,UAAU,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAC7B,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CACvB,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CACnC,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CACzB,cAAc,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CACrC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CACvB,cAAc,CAAC,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC,CACrD,aAAa,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,CACnD,OAAO,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,EACvC,CACH,CAAA;AACH,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,SAAS,EAAE;QACT,eAAe,EAAE,SAAS;KAC3B;CACF,CAAC,CAAA","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\n\nimport { ContentPadding, FitMode, OnErrorEventPayload, OnLoadCompleteEventPayload, OnPageChangedEventPayload } from './types';\nimport { NativeSyntheticEvent, StyleProp, StyleSheet, ViewStyle } from 'react-native';\nimport { forwardNativeEventTo } from './utils';\n\ntype BaseProps = {\n style?: StyleProp<ViewStyle>;\n /**\n * The file URI. Accepts a remote resource (e.g. via HTTPs) or a local file path (e.g. file:///)\n */\n uri: string;\n password?: string;\n pagingEnabled?: boolean\n disableDoubleTapToZoom?: boolean\n horizontal?: boolean\n pageGap?: number\n contentPadding?: ContentPadding\n fitMode?: FitMode\n}\n\ntype NativePdfViewProps = BaseProps & {\n onLoadComplete?: (event: NativeSyntheticEvent<OnLoadCompleteEventPayload>) => void;\n onPageChanged?: (event: NativeSyntheticEvent<OnPageChangedEventPayload>) => void;\n onError?: (event: NativeSyntheticEvent<OnErrorEventPayload>) => void;\n};\n\nconst NativePdfView: React.ComponentType<NativePdfViewProps> = requireNativeView('KJExpoPdf');\n\n// -----------\n\nexport type PdfViewProps = BaseProps & {\n onLoadComplete?: (params: OnLoadCompleteEventPayload) => void,\n onPageChanged?: (params: OnPageChangedEventPayload) => void,\n onError?: (params: OnErrorEventPayload) => void\n};\n\nexport const PdfView = ({\n style,\n onLoadComplete,\n onError,\n onPageChanged,\n ...props\n}: PdfViewProps) => {\n return (\n <NativePdfView\n style={[styles.container, style]}\n uri={props.uri}\n disableDoubleTapToZoom={props.disableDoubleTapToZoom}\n horizontal={props.horizontal}\n pageGap={props.pageGap}\n pagingEnabled={props.pagingEnabled}\n password={props.password}\n contentPadding={props.contentPadding}\n fitMode={props.fitMode}\n onLoadComplete={forwardNativeEventTo(onLoadComplete)}\n onPageChanged={forwardNativeEventTo(onPageChanged)}\n onError={forwardNativeEventTo(onError)}\n />\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n backgroundColor: '#eeeeee'\n }\n})\n"]}
1
+ {"version":3,"file":"pdf-view.js","sourceRoot":"","sources":["../src/pdf-view.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAmC,UAAU,EAAa,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAwB/C,MAAM,aAAa,GAA4C,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAU9F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,KAAK,EACL,cAAc,EACd,OAAO,EACP,aAAa,EACb,GAAG,KAAK,EACK,EAAE,EAAE;IACjB,OAAO,CACL,CAAC,aAAa,CACZ,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CACjC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CACf,eAAe,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CACvC,UAAU,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAC7B,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CACvB,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CACnC,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CACzB,cAAc,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CACrC,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CACvB,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAC3B,cAAc,CAAC,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC,CACrD,aAAa,CAAC,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,CACnD,OAAO,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC,EACvC,CACH,CAAA;AACH,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,SAAS,EAAE;QACT,eAAe,EAAE,SAAS;KAC3B;CACF,CAAC,CAAA","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\n\nimport { ContentPadding, FitMode, OnErrorEventPayload, OnLoadCompleteEventPayload, OnPageChangedEventPayload } from './types';\nimport { NativeSyntheticEvent, StyleProp, StyleSheet, ViewStyle } from 'react-native';\nimport { forwardNativeEventTo } from './utils';\n\ntype BaseProps = {\n style?: StyleProp<ViewStyle>;\n /**\n * The file URI. Accepts a remote resource (e.g. via HTTPs) or a local file path (e.g. file:///)\n */\n uri: string;\n password?: string;\n pagingEnabled?: boolean\n doubleTapToZoom?: boolean\n horizontal?: boolean\n pageGap?: number\n contentPadding?: ContentPadding\n fitMode?: FitMode\n autoScale?: boolean\n}\n\ntype NativePdfViewProps = BaseProps & {\n onLoadComplete?: (event: NativeSyntheticEvent<OnLoadCompleteEventPayload>) => void;\n onPageChanged?: (event: NativeSyntheticEvent<OnPageChangedEventPayload>) => void;\n onError?: (event: NativeSyntheticEvent<OnErrorEventPayload>) => void;\n};\n\nconst NativePdfView: React.ComponentType<NativePdfViewProps> = requireNativeView('KJExpoPdf');\n\n// -----------\n\nexport type PdfViewProps = BaseProps & {\n onLoadComplete?: (params: OnLoadCompleteEventPayload) => void,\n onPageChanged?: (params: OnPageChangedEventPayload) => void,\n onError?: (params: OnErrorEventPayload) => void\n};\n\nexport const PdfView = ({\n style,\n onLoadComplete,\n onError,\n onPageChanged,\n ...props\n}: PdfViewProps) => {\n return (\n <NativePdfView\n style={[styles.container, style]}\n uri={props.uri}\n doubleTapToZoom={props.doubleTapToZoom}\n horizontal={props.horizontal}\n pageGap={props.pageGap}\n pagingEnabled={props.pagingEnabled}\n password={props.password}\n contentPadding={props.contentPadding}\n fitMode={props.fitMode}\n autoScale={props.autoScale}\n onLoadComplete={forwardNativeEventTo(onLoadComplete)}\n onPageChanged={forwardNativeEventTo(onPageChanged)}\n onError={forwardNativeEventTo(onError)}\n />\n )\n}\n\nconst styles = StyleSheet.create({\n container: {\n backgroundColor: '#eeeeee'\n }\n})\n"]}
package/bunfig.toml ADDED
@@ -0,0 +1,2 @@
1
+ [install.registry]
2
+ url = "https://registry.npmjs.org"
@@ -27,16 +27,16 @@ public class KJExpoPdfModule: Module {
27
27
  view.setPagingEnabled(enabled)
28
28
  }
29
29
 
30
- Prop("disableDoubleTapToZoom") { (view: KJExpoPdfView, disabled: Bool?) in
31
- view.setDoubleTapZoomEnabled(disabled != true)
30
+ Prop("doubleTapToZoom") { (view: KJExpoPdfView, enabled: Bool?) in
31
+ view.setDoubleTapZoomEnabled(enabled)
32
32
  }
33
33
 
34
34
  Prop("horizontal") { (view: KJExpoPdfView, enabled: Bool?) in
35
35
  view.setHorizontalModeEnabled(enabled)
36
36
  }
37
37
 
38
- Prop("pageGap") { (view: KJExpoPdfView, gapPx: Int?) in
39
- view.setPageGap(gapPx)
38
+ Prop("pageGap") { (view: KJExpoPdfView, gap: Int?) in
39
+ view.setPageGap(gap)
40
40
  }
41
41
 
42
42
  Prop("contentPadding") { (view: KJExpoPdfView, contentPadding: ContentPadding?) in
@@ -46,6 +46,10 @@ public class KJExpoPdfModule: Module {
46
46
  Prop("fitMode") { (view: KJExpoPdfView, fitMode: FitMode?) in
47
47
  view.setFitMode(fitMode)
48
48
  }
49
+
50
+ Prop("autoScale") { (view: KJExpoPdfView, enabled: Bool?) in
51
+ view.setAutoScaleEnabled(enabled)
52
+ }
49
53
  }
50
54
  }
51
55
  }
@@ -1,3 +1,4 @@
1
+ import CoreGraphics
1
2
  import ExpoModulesCore
2
3
  import PDFKit
3
4
  import SwiftUI
@@ -10,6 +11,7 @@ class KJExpoPdfView: ExpoView {
10
11
  static let DEFAULT_PAGE_GAP = 0
11
12
  static let DEFAULT_CONTENT_PADDING = UIEdgeInsets.zero
12
13
  static let DEFAULT_FIT_MODE = FitMode.both
14
+ static let DEFAULT_AUTO_SCALE_ENABLED = true
13
15
 
14
16
  let onLoadComplete = EventDispatcher()
15
17
  let onPageChanged = EventDispatcher()
@@ -24,6 +26,10 @@ class KJExpoPdfView: ExpoView {
24
26
 
25
27
  private let pdfView = PDFView()
26
28
 
29
+ private var lastLayoutBounds: CGRect = .zero
30
+ private var isFirstLayoutComplete: Bool = false
31
+
32
+ // - MARK: Props
27
33
  private var documentURL: URL? = nil
28
34
  private var password: String? = nil
29
35
  private var isPagingEnabled: Bool = DEFAULT_PAGING_ENABLED
@@ -32,6 +38,7 @@ class KJExpoPdfView: ExpoView {
32
38
  private var pageGap: Int = DEFAULT_PAGE_GAP
33
39
  private var contentPadding: UIEdgeInsets = DEFAULT_CONTENT_PADDING
34
40
  private var fitMode: FitMode = DEFAULT_FIT_MODE
41
+ private var isAutoScaleEnabled: Bool = DEFAULT_AUTO_SCALE_ENABLED
35
42
 
36
43
  required init(appContext: AppContext? = nil) {
37
44
  super.init(appContext: appContext)
@@ -43,21 +50,40 @@ class KJExpoPdfView: ExpoView {
43
50
  // style prop in the component (`style={{ backgroundColor: '#eee' }}`).
44
51
  self.pdfView.backgroundColor = .clear
45
52
 
46
- // We calculate the scaling manually via PDFView.scaleToFit(contentPadding:)
53
+ // We calculate the scaling manually via PDFView.scaleToFit(contentPadding:) and don't rely
54
+ // on native autoscaling because it doesn't take into account the content padding.
55
+ // - TODO: Maybe allow native autoscaling if no content padding is set? as that's the only reason we need the manual method.
47
56
  self.pdfView.autoScales = false
48
57
 
49
58
  addSubview(pdfView)
50
-
51
59
  setupListeners()
52
60
  }
53
61
 
54
62
  override func layoutSubviews() {
63
+ // This method sometimes gets called with either one of bounds.height or bounds.width set as 0 initially
64
+ // so we defer until both values are available.
65
+ // - By delaying calling until the size in both dimensions are correct we are able to prevent duplicate measurements
66
+ // and detect the initial layout action.
67
+ let bothNewBoundsAreSet = bounds.width > 0 && bounds.height > 0
68
+ let previousBoundsAreSet = self.lastLayoutBounds.width > 0 || self.lastLayoutBounds.height > 0
69
+ let finishedInitialLayout = bothNewBoundsAreSet || previousBoundsAreSet
70
+ if !finishedInitialLayout {
71
+ return
72
+ }
73
+
55
74
  super.layoutSubviews()
56
- pdfView.frame = bounds
75
+ self.pdfView.frame = bounds
76
+ self.lastLayoutBounds = bounds
77
+
78
+ // Force auto scale the document to fit the view on the intial layout by default
79
+ // - Do not autoscale on subsequent layouts if the consumer has manually disabled it
80
+ if !self.isFirstLayoutComplete || self.isAutoScaleEnabled {
81
+ // Maintain insets on rotation and reset the reading position (current scroll position) only on
82
+ // the first layout.
83
+ self.autoScale(resetScrollOffset: !self.isFirstLayoutComplete)
84
+ }
57
85
 
58
- // Maintain insets on rotation, but don't reset reading position
59
- self.pdfView.scaleToFit(
60
- contentPadding: self.contentPadding, fitMode: self.fitMode, resetOffset: false)
86
+ self.isFirstLayoutComplete = true
61
87
  }
62
88
 
63
89
  deinit {
@@ -122,7 +148,7 @@ class KJExpoPdfView: ExpoView {
122
148
  right: padding.right - margins.right
123
149
  )
124
150
  self.pdfView.scaleToFit(
125
- contentPadding: self.contentPadding, fitMode: self.fitMode, resetOffset: false)
151
+ contentPadding: self.contentPadding, fitMode: self.fitMode, resetScrollOffset: false)
126
152
  }
127
153
 
128
154
  func setContentPadding(_ padding: UIEdgeInsets?) {
@@ -142,14 +168,24 @@ class KJExpoPdfView: ExpoView {
142
168
  right: padding.right - margins.right
143
169
  )
144
170
  self.pdfView.scaleToFit(
145
- contentPadding: self.contentPadding, fitMode: self.fitMode, resetOffset: false)
171
+ contentPadding: self.contentPadding, fitMode: self.fitMode, resetScrollOffset: false)
146
172
  }
147
173
 
148
174
  func setFitMode(_ mode: FitMode?) {
149
175
  self.fitMode = mode ?? Self.DEFAULT_FIT_MODE
150
176
 
151
177
  self.pdfView.scaleToFit(
152
- contentPadding: self.contentPadding, fitMode: self.fitMode, resetOffset: false)
178
+ contentPadding: self.contentPadding, fitMode: self.fitMode, resetScrollOffset: false)
179
+ }
180
+
181
+ func setAutoScaleEnabled(_ enabled: Bool?) {
182
+ self.isAutoScaleEnabled = enabled ?? Self.DEFAULT_AUTO_SCALE_ENABLED
183
+
184
+ // Re-scale because a consumer will always expect a change when changing this prop.
185
+ if enabled == true {
186
+ self.pdfView.scaleToFit(
187
+ contentPadding: self.contentPadding, fitMode: self.fitMode, resetScrollOffset: true)
188
+ }
153
189
  }
154
190
 
155
191
  @objc private func handlePageChange() {
@@ -185,14 +221,9 @@ class KJExpoPdfView: ExpoView {
185
221
  )
186
222
  }
187
223
  }
188
-
189
224
  self.pdfView.document = document
190
225
 
191
- // Dispatch async to allow PDFView to finish its initial layout
192
- DispatchQueue.main.async {
193
- self.pdfView.scaleToFit(
194
- contentPadding: self.contentPadding, fitMode: self.fitMode, resetOffset: true)
195
- }
226
+ self.autoScale(resetScrollOffset: !self.isFirstLayoutComplete)
196
227
 
197
228
  self.onLoadComplete([
198
229
  "pageCount": document.pageCount
@@ -224,6 +255,17 @@ class KJExpoPdfView: ExpoView {
224
255
  return document
225
256
  }
226
257
 
258
+ private func autoScale(resetScrollOffset: Bool) {
259
+ // Dispatch async to allow PDFView to finish its initial layout
260
+ DispatchQueue.main.async {
261
+ self.pdfView.scaleToFit(
262
+ contentPadding: self.contentPadding,
263
+ fitMode: self.fitMode,
264
+ resetScrollOffset: resetScrollOffset
265
+ )
266
+ }
267
+ }
268
+
227
269
  private func setupListeners() {
228
270
  NotificationCenter.default.addObserver(
229
271
  self,
@@ -5,30 +5,31 @@
5
5
  // Created by Kishan Jadav on 05/01/2026.
6
6
  //
7
7
 
8
+ import ExpoModulesCore
8
9
  import PDFKit
9
10
 
10
11
  extension PDFView {
11
- func scaleToFit(contentPadding: UIEdgeInsets, fitMode: FitMode, resetOffset: Bool = false) {
12
+ func scaleToFit(contentPadding: UIEdgeInsets, fitMode: FitMode, resetScrollOffset: Bool = false) {
12
13
  guard let page = self.currentPage else {
13
14
  return
14
15
  }
15
-
16
+
16
17
  let viewSize = self.bounds.size
17
18
  let pageSize = page.bounds(for: self.displayBox).size
18
-
19
+
19
20
  // Ensure we have valid dimensions to avoid division by zero
20
21
  guard viewSize.width > 0, pageSize.width > 0, pageSize.height > 0 else {
21
22
  return
22
23
  }
23
-
24
+
24
25
  // Calculate the available space (View size minus Padding)
25
26
  let availableWidth = viewSize.width - contentPadding.left - contentPadding.right
26
27
  let availableHeight = viewSize.height - contentPadding.top - contentPadding.bottom
27
-
28
+
28
29
  // Calculate potential scale factors
29
30
  let widthScale = availableWidth / pageSize.width
30
31
  let heightScale = availableHeight / pageSize.height
31
-
32
+
32
33
  // Determine the target scale based on the requested FitMode
33
34
  let targetScale: CGFloat
34
35
  switch fitMode {
@@ -40,22 +41,22 @@ extension PDFView {
40
41
  // "Aspect Fit": Choose the smaller scale to ensure the whole page is visible
41
42
  targetScale = min(widthScale, heightScale)
42
43
  }
43
-
44
+
44
45
  // Apply new scale factor
45
46
  if abs(self.scaleFactor - targetScale) > 0.001 {
46
- self.minScaleFactor = targetScale // Prevent zooming out further than the fit
47
+ self.minScaleFactor = targetScale // Prevent zooming out further than the fit
47
48
  self.scaleFactor = targetScale
48
49
  }
49
-
50
- self.applyContentPadding(contentPadding, resetOffset: resetOffset)
50
+
51
+ self.applyContentPadding(contentPadding, resetScrollOffset: resetScrollOffset)
51
52
  }
52
-
53
- func applyContentPadding(_ contentPadding: UIEdgeInsets, resetOffset: Bool = false) {
53
+
54
+ func applyContentPadding(_ contentPadding: UIEdgeInsets, resetScrollOffset: Bool = false) {
54
55
  // Iterate through the PDFView's subviews to find the scroll view
55
56
  if let scrollView = self.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView {
56
57
  scrollView.contentInset = contentPadding
57
58
 
58
- if resetOffset {
59
+ if resetScrollOffset {
59
60
  var offset = scrollView.contentOffset
60
61
  if self.displayDirection == .horizontal {
61
62
  offset.x = -contentPadding.left
@@ -66,24 +67,28 @@ extension PDFView {
66
67
  }
67
68
  }
68
69
  }
69
-
70
+
70
71
  func toggleDoubleTapToZoom(_ enabled: Bool) {
71
72
  // Iterate through the PDFView's subviews to find the scroll view
72
73
  for subview in self.subviews {
73
74
  if let gestureRecognizers = subview.gestureRecognizers {
74
75
  for gesture in gestureRecognizers {
75
- if let tapGesture = gesture as? UITapGestureRecognizer, tapGesture.numberOfTapsRequired == 2 {
76
+ if let tapGesture = gesture as? UITapGestureRecognizer,
77
+ tapGesture.numberOfTapsRequired == 2
78
+ {
76
79
  // Disable the double-tap recognizer
77
80
  tapGesture.isEnabled = enabled
78
81
  }
79
82
  }
80
83
  }
81
-
84
+
82
85
  // Sometimes the gesture is deeper, so we check sub-subviews (like the document view)
83
86
  for internalSubview in subview.subviews {
84
87
  if let gestureRecognizers = internalSubview.gestureRecognizers {
85
88
  for gesture in gestureRecognizers {
86
- if let tapGesture = gesture as? UITapGestureRecognizer, tapGesture.numberOfTapsRequired == 2 {
89
+ if let tapGesture = gesture as? UITapGestureRecognizer,
90
+ tapGesture.numberOfTapsRequired == 2
91
+ {
87
92
  tapGesture.isEnabled = enabled
88
93
  }
89
94
  }
package/package.json CHANGED
@@ -1,40 +1,9 @@
1
1
  {
2
2
  "name": "@kishannareshpal/expo-pdf",
3
- "version": "0.1.0",
4
- "description": "A cross-platform, performant PDF viewer component for React Native and Expo",
5
- "main": "build/index.js",
6
- "types": "build/index.d.ts",
7
- "scripts": {
8
- "build": "expo-module build",
9
- "clean": "expo-module clean",
10
- "lint": "expo-module lint",
11
- "test": "expo-module test",
12
- "prepublishOnly": "expo-module prepublishOnly",
13
- "expo-module": "expo-module",
14
- "open:ios": "xed example/ios",
15
- "open:android": "open -a \"Android Studio\" example/android",
16
- "format": "prettier --write .",
17
- "format:check": "prettier --check .",
18
- "prepare": "husky; expo-module prepare"
19
- },
20
- "keywords": [
21
- "react-native",
22
- "expo",
23
- "@kishannareshpal/expo-pdf",
24
- "rn-pdf",
25
- "react-native-pdf",
26
- "expo-pdf",
27
- "pdf",
28
- "expopdf"
29
- ],
30
- "repository": "https://github.com/kishannareshpal/expo-pdf",
31
- "bugs": {
32
- "url": "https://github.com/kishannareshpal/expo-pdf/issues"
33
- },
3
+ "version": "0.2.1",
34
4
  "author": "Kishan Jadav <kishan_jadav@hotmail.com> (https://github.com/kishannareshpal)",
35
- "license": "MIT",
36
- "homepage": "https://github.com/kishannareshpal/expo-pdf#readme",
37
- "dependencies": {},
5
+ "repository": "https://github.com/kishannareshpal/expo-pdf",
6
+ "main": "build/index.js",
38
7
  "devDependencies": {
39
8
  "@types/react": "~19.1.0",
40
9
  "expo": "^54.0.27",
@@ -49,6 +18,22 @@
49
18
  "react": "*",
50
19
  "react-native": "*"
51
20
  },
21
+ "bugs": {
22
+ "url": "https://github.com/kishannareshpal/expo-pdf/issues"
23
+ },
24
+ "description": "A cross-platform, performant PDF viewer component for React Native and Expo",
25
+ "homepage": "https://github.com/kishannareshpal/expo-pdf#readme",
26
+ "keywords": [
27
+ "react-native",
28
+ "expo",
29
+ "@kishannareshpal/expo-pdf",
30
+ "rn-pdf",
31
+ "react-native-pdf",
32
+ "expo-pdf",
33
+ "pdf",
34
+ "expopdf"
35
+ ],
36
+ "license": "MIT",
52
37
  "lint-staged": {
53
38
  "*.{js,jsx,ts,tsx,json,css,md,yml,yaml}": [
54
39
  "prettier --write"
@@ -56,5 +41,19 @@
56
41
  "*.{java,kt,swift,h,m,mm}": [
57
42
  "prettier --write"
58
43
  ]
59
- }
60
- }
44
+ },
45
+ "scripts": {
46
+ "build": "bun run em build",
47
+ "clean": "bun run em clean",
48
+ "lint": "bun run em lint",
49
+ "test": "bun run em test",
50
+ "prepublishOnly": "bun run em prepublishOnly",
51
+ "em": "bunx expo-module",
52
+ "open:ios": "xed example/ios",
53
+ "open:android": "open -a \"Android Studio\" example/android",
54
+ "format": "bunx prettier --write .",
55
+ "format:check": "bunx prettier --check .",
56
+ "prepare": "bunx husky; bun run em prepare"
57
+ },
58
+ "types": "build/index.d.ts"
59
+ }
package/src/pdf-view.tsx CHANGED
@@ -13,11 +13,12 @@ type BaseProps = {
13
13
  uri: string;
14
14
  password?: string;
15
15
  pagingEnabled?: boolean
16
- disableDoubleTapToZoom?: boolean
16
+ doubleTapToZoom?: boolean
17
17
  horizontal?: boolean
18
18
  pageGap?: number
19
19
  contentPadding?: ContentPadding
20
20
  fitMode?: FitMode
21
+ autoScale?: boolean
21
22
  }
22
23
 
23
24
  type NativePdfViewProps = BaseProps & {
@@ -47,13 +48,14 @@ export const PdfView = ({
47
48
  <NativePdfView
48
49
  style={[styles.container, style]}
49
50
  uri={props.uri}
50
- disableDoubleTapToZoom={props.disableDoubleTapToZoom}
51
+ doubleTapToZoom={props.doubleTapToZoom}
51
52
  horizontal={props.horizontal}
52
53
  pageGap={props.pageGap}
53
54
  pagingEnabled={props.pagingEnabled}
54
55
  password={props.password}
55
56
  contentPadding={props.contentPadding}
56
57
  fitMode={props.fitMode}
58
+ autoScale={props.autoScale}
57
59
  onLoadComplete={forwardNativeEventTo(onLoadComplete)}
58
60
  onPageChanged={forwardNativeEventTo(onPageChanged)}
59
61
  onError={forwardNativeEventTo(onError)}