react-native-optimized-pdf 1.1.0 → 1.3.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.
@@ -3,29 +3,20 @@ import Foundation
3
3
  /// Errors that can occur during PDF operations.
4
4
  enum PDFError: Error, LocalizedError {
5
5
  case emptySource
6
- case invalidPath(String)
7
6
  case documentLoadFailed(String)
8
7
  case passwordRequired
9
8
  case invalidPassword
10
- case pageNotFound(Int)
11
- case renderingFailed
12
9
 
13
10
  var errorDescription: String? {
14
11
  switch self {
15
12
  case .emptySource:
16
13
  return "PDF source path is empty"
17
- case .invalidPath(let path):
18
- return "Invalid PDF path: \(path)"
19
14
  case .documentLoadFailed(let path):
20
15
  return "Failed to open PDF at: \(path)"
21
16
  case .passwordRequired:
22
17
  return "PDF is password protected"
23
18
  case .invalidPassword:
24
19
  return "Invalid password for PDF"
25
- case .pageNotFound(let index):
26
- return "Page not found at index: \(index)"
27
- case .renderingFailed:
28
- return "Failed to render PDF page"
29
20
  }
30
21
  }
31
22
 
@@ -17,32 +17,4 @@ final class OptimizedPDFViewManager: RCTViewManager {
17
17
  override static func requiresMainQueueSetup() -> Bool {
18
18
  true
19
19
  }
20
-
21
- // MARK: - Exported Methods
22
-
23
- /// Navigates to a specific page in the PDF.
24
- /// - Parameters:
25
- /// - node: The React Native view tag.
26
- /// - page: The page index to navigate to (0-based).
27
- @objc func goToPage(_ node: NSNumber, page: NSNumber) {
28
- DispatchQueue.main.async { [weak self] in
29
- guard let self = self,
30
- let pdfView = self.bridge?.uiManager.view(forReactTag: node) as? OptimizedPDFView else {
31
- return
32
- }
33
- pdfView.goToPage(page.intValue)
34
- }
35
- }
36
-
37
- /// Resets the zoom level to fit the page.
38
- /// - Parameter node: The React Native view tag.
39
- @objc func resetZoom(_ node: NSNumber) {
40
- DispatchQueue.main.async { [weak self] in
41
- guard let self = self,
42
- let pdfView = self.bridge?.uiManager.view(forReactTag: node) as? OptimizedPDFView else {
43
- return
44
- }
45
- pdfView.resetZoom()
46
- }
47
- }
48
20
  }
@@ -6,8 +6,6 @@
6
6
  */
7
7
 
8
8
  #import <React/RCTViewManager.h>
9
- #import <React/RCTUIManager.h>
10
- #import <React/RCTBridgeModule.h>
11
9
 
12
10
  @interface RCT_EXTERN_MODULE(OptimizedPdfViewManager, RCTViewManager)
13
11
 
@@ -42,13 +40,4 @@ RCT_EXPORT_VIEW_PROPERTY(onPageCount, RCTDirectEventBlock)
42
40
  /// Called when the PDF requires a password to open.
43
41
  RCT_EXPORT_VIEW_PROPERTY(onPasswordRequired, RCTDirectEventBlock)
44
42
 
45
- #pragma mark - Native Methods
46
-
47
- /// Navigates to a specific page in the PDF.
48
- RCT_EXTERN_METHOD(goToPage:(nonnull NSNumber *)node
49
- page:(nonnull NSNumber *)page)
50
-
51
- /// Resets the zoom level to fit the page.
52
- RCT_EXTERN_METHOD(resetZoom:(nonnull NSNumber *)node)
53
-
54
43
  @end
@@ -1,18 +1,16 @@
1
1
  import UIKit
2
2
  import React
3
-
4
- /// Protocol for receiving PDF view events.
5
- @objc protocol OptimizedPDFViewDelegate: AnyObject {
6
- @objc optional func pdfView(_ pdfView: OptimizedPDFView, didFailWithError error: Error)
7
- @objc optional func pdfView(_ pdfView: OptimizedPDFView, didLoadWithPageCount pageCount: Int)
8
- @objc optional func pdfView(_ pdfView: OptimizedPDFView, didDisplayPage page: Int, size: CGSize)
9
- @objc optional func pdfViewDidRequestPassword(_ pdfView: OptimizedPDFView)
10
- }
3
+ import PDFKit
11
4
 
12
5
  /// A high-performance PDF view using CATiledLayer for smooth zooming and scrolling.
13
6
  ///
14
7
  /// This view is optimized for React Native integration, providing callbacks for
15
8
  /// load completion, errors, and page navigation events.
9
+ ///
10
+ /// Naming note: the Swift type is `OptimizedPDFView` while its `@objc` export is
11
+ /// `OptimizedPdfView`, and the Objective-C manager/registration is
12
+ /// `OptimizedPdfViewManager`. The `Pdf` spellings are the native bridge contract
13
+ /// with JavaScript and must not be renamed.
16
14
  @objc(OptimizedPdfView)
17
15
  final class OptimizedPDFView: UIScrollView {
18
16
 
@@ -33,7 +31,7 @@ final class OptimizedPDFView: UIScrollView {
33
31
  }
34
32
 
35
33
  /// Maximum zoom scale.
36
- @objc var maximumZoom: NSNumber = 5.0 {
34
+ @objc var maximumZoom: NSNumber = 3 {
37
35
  didSet {
38
36
  configuration.maximumZoom = CGFloat(truncating: maximumZoom)
39
37
  applyZoomConfiguration()
@@ -44,7 +42,7 @@ final class OptimizedPDFView: UIScrollView {
44
42
  @objc var enableAntialiasing: Bool = true {
45
43
  didSet {
46
44
  configuration.enableAntialiasing = enableAntialiasing
47
- tiledPageView.enableAntialiasing = enableAntialiasing
45
+ tiledPageView?.enableAntialiasing = enableAntialiasing
48
46
  }
49
47
  }
50
48
 
@@ -65,15 +63,14 @@ final class OptimizedPDFView: UIScrollView {
65
63
 
66
64
  // MARK: - Public Properties
67
65
 
68
- weak var pdfDelegate: OptimizedPDFViewDelegate?
69
-
70
66
  /// Current number of pages in the document.
71
67
  private(set) var pageCount: Int = 0
72
68
 
73
69
  // MARK: - Private Properties
74
70
 
75
71
  private var pdfDocument: CGPDFDocument?
76
- private let tiledPageView: TiledPDFPageView
72
+ private var tiledPageView: TiledPDFPageView!
73
+ private var pdfURL: URL?
77
74
  private var configuration = PDFConfiguration.default
78
75
  private let documentLoader: PDFDocumentLoading
79
76
 
@@ -81,7 +78,6 @@ final class OptimizedPDFView: UIScrollView {
81
78
  private var needsLoad = false
82
79
  private var lastBoundsSize: CGSize = .zero
83
80
  private var currentPageRect: CGRect?
84
- private var initialZoomScale: CGFloat = 1.0
85
81
 
86
82
  // MARK: - Initialization
87
83
 
@@ -99,14 +95,6 @@ final class OptimizedPDFView: UIScrollView {
99
95
  setupView()
100
96
  }
101
97
 
102
- /// Initializes with a custom document loader (useful for testing).
103
- init(frame: CGRect, documentLoader: PDFDocumentLoading) {
104
- self.tiledPageView = TiledPDFPageView(frame: frame)
105
- self.documentLoader = documentLoader
106
- super.init(frame: frame)
107
- setupView()
108
- }
109
-
110
98
  // MARK: - Setup
111
99
 
112
100
  private func setupView() {
@@ -135,7 +123,6 @@ final class OptimizedPDFView: UIScrollView {
135
123
 
136
124
  let fitScale = calculateFitScale(for: pageRect)
137
125
  minimumZoomScale = fitScale
138
- initialZoomScale = fitScale
139
126
  }
140
127
  }
141
128
 
@@ -145,6 +132,8 @@ private extension OptimizedPDFView {
145
132
 
146
133
  func handleSourceChange() {
147
134
  resetDocument()
135
+ pdfURL = nil
136
+ FlattenedPageCache.shared.removeAll()
148
137
  pendingPageIndex = page.intValue
149
138
  needsLoad = true
150
139
  setNeedsLayout()
@@ -173,6 +162,9 @@ private extension OptimizedPDFView {
173
162
  func loadDocument() {
174
163
  guard !source.isEmpty else { return }
175
164
 
165
+ let path = normalizedPDFPath(from: source)
166
+ pdfURL = URL(fileURLWithPath: path)
167
+
176
168
  let result = documentLoader.loadDocument(from: source, password: configuration.password)
177
169
 
178
170
  switch result {
@@ -192,7 +184,6 @@ private extension OptimizedPDFView {
192
184
  DispatchQueue.main.async { [weak self] in
193
185
  guard let self = self else { return }
194
186
  self.onPageCount?(["numberOfPages": NSNumber(value: self.pageCount)])
195
- self.pdfDelegate?.pdfView?(self, didLoadWithPageCount: self.pageCount)
196
187
  }
197
188
 
198
189
  // Display pending or first page
@@ -207,12 +198,10 @@ private extension OptimizedPDFView {
207
198
  DispatchQueue.main.async { [weak self] in
208
199
  guard let self = self else { return }
209
200
  self.onPasswordRequired?([:])
210
- self.pdfDelegate?.pdfViewDidRequestPassword?(self)
211
201
  }
212
202
  }
213
203
 
214
204
  onError?(error.eventPayload)
215
- pdfDelegate?.pdfView?(self, didFailWithError: error)
216
205
  }
217
206
 
218
207
  func clampPageIndex(_ index: Int, for document: CGPDFDocument) -> Int {
@@ -234,7 +223,22 @@ private extension OptimizedPDFView {
234
223
  currentPageRect = pageRect
235
224
 
236
225
  prepareForPageDisplay()
237
- configureTiledView(for: page, rect: pageRect)
226
+
227
+ tiledPageView?.cancel()
228
+ tiledPageView?.removeFromSuperview()
229
+
230
+ let newView = TiledPDFPageView(frame: CGRect(origin: .zero, size: pageRect.size))
231
+ newView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
232
+ newView.configuration = configuration
233
+ newView.pdfURL = pdfURL
234
+ newView.pageIndex = index
235
+ newView.pdfPage = page
236
+ addSubview(newView)
237
+ tiledPageView = newView
238
+
239
+ contentSize = pageRect.size
240
+ tiledPageView.preparePage()
241
+
238
242
  applyFitScale(for: pageRect)
239
243
  centerContent()
240
244
  notifyPageDisplayed(index: index, size: pageRect.size)
@@ -245,15 +249,9 @@ private extension OptimizedPDFView {
245
249
  contentOffset = .zero
246
250
  }
247
251
 
248
- func configureTiledView(for page: CGPDFPage, rect: CGRect) {
249
- tiledPageView.updateFrame(for: page)
250
- contentSize = rect.size
251
- }
252
-
253
252
  func applyFitScale(for pageRect: CGRect) {
254
253
  let fitScale = calculateFitScale(for: pageRect)
255
254
  minimumZoomScale = fitScale
256
- initialZoomScale = fitScale
257
255
  setZoomScale(fitScale, animated: false)
258
256
  }
259
257
 
@@ -267,7 +265,6 @@ private extension OptimizedPDFView {
267
265
  DispatchQueue.main.async { [weak self] in
268
266
  guard let self = self else { return }
269
267
  self.onLoadComplete?(payload)
270
- self.pdfDelegate?.pdfView?(self, didDisplayPage: index + 1, size: size)
271
268
  }
272
269
  }
273
270
  }
@@ -362,23 +359,3 @@ extension OptimizedPDFView {
362
359
  centerContent()
363
360
  }
364
361
  }
365
-
366
- // MARK: - Public Methods
367
-
368
- extension OptimizedPDFView {
369
-
370
- /// Resets the zoom to fit the page.
371
- @objc func resetZoom() {
372
- UIView.animate(withDuration: configuration.zoomResetAnimationDuration) { [weak self] in
373
- guard let self = self else { return }
374
- self.setZoomScale(self.initialZoomScale, animated: false)
375
- self.centerContent()
376
- }
377
- }
378
-
379
- /// Navigates to a specific page.
380
- /// - Parameter index: The page index (0-based).
381
- @objc func goToPage(_ index: Int) {
382
- page = NSNumber(value: index)
383
- }
384
- }
@@ -1,44 +1,100 @@
1
1
  import UIKit
2
2
  import CoreGraphics
3
+ import PDFKit
3
4
 
4
5
  /// A view that renders a PDF page using CATiledLayer for efficient tiled rendering.
5
6
  ///
6
7
  /// CATiledLayer divides the content into tiles, allowing smooth zooming and scrolling
7
8
  /// without rendering the entire PDF at once. This is essential for large PDF documents.
9
+
10
+ // MARK: - Global cache of flattened pages
11
+ final class FlattenedPageCache {
12
+ static let shared = FlattenedPageCache()
13
+
14
+ private let cache = NSCache<NSString, FlattenedPageEntry>()
15
+
16
+ private init() {
17
+ cache.countLimit = 10
18
+ }
19
+
20
+ func entry(forKey key: String) -> FlattenedPageEntry? {
21
+ cache.object(forKey: key as NSString)
22
+ }
23
+
24
+ func setEntry(_ entry: FlattenedPageEntry, forKey key: String) {
25
+ cache.setObject(entry, forKey: key as NSString)
26
+ }
27
+
28
+ func removeAll() {
29
+ cache.removeAllObjects()
30
+ }
31
+ }
32
+
33
+ final class FlattenedPageEntry: NSObject {
34
+ let document: CGPDFDocument
35
+ let page: CGPDFPage
36
+
37
+ init(document: CGPDFDocument, page: CGPDFPage) {
38
+ self.document = document
39
+ self.page = page
40
+ }
41
+ }
42
+
43
+ // MARK: - Atomic flag for thread-safe cancellation
44
+
45
+ final class OSAtomicFlag {
46
+ private var _value: Bool = false
47
+ private var _lock = os_unfair_lock()
48
+
49
+ func set() {
50
+ os_unfair_lock_lock(&_lock)
51
+ _value = true
52
+ os_unfair_lock_unlock(&_lock)
53
+ }
54
+
55
+ func reset() {
56
+ os_unfair_lock_lock(&_lock)
57
+ _value = false
58
+ os_unfair_lock_unlock(&_lock)
59
+ }
60
+
61
+ func isSet() -> Bool {
62
+ os_unfair_lock_lock(&_lock)
63
+ let v = _value
64
+ os_unfair_lock_unlock(&_lock)
65
+ return v
66
+ }
67
+ }
68
+
69
+ // MARK: - TiledPDFPageView
70
+
8
71
  final class TiledPDFPageView: UIView {
9
72
 
10
73
  // MARK: - Properties
11
74
 
12
- /// The PDF page to render.
13
75
  var pdfPage: CGPDFPage? {
14
- didSet {
15
- setNeedsDisplay()
16
- }
76
+ didSet { setNeedsDisplay() }
17
77
  }
18
78
 
19
- /// Whether antialiasing is enabled for rendering.
79
+ var pdfURL: URL?
80
+ var pageIndex: Int = 0
81
+
20
82
  var enableAntialiasing: Bool = true {
21
- didSet {
22
- setNeedsDisplay()
23
- }
83
+ didSet { setNeedsDisplay() }
24
84
  }
25
85
 
26
- /// The configuration for tiled rendering.
27
86
  var configuration: PDFConfiguration = .default {
28
- didSet {
29
- applyConfiguration()
30
- }
87
+ didSet { applyConfiguration() }
31
88
  }
32
89
 
33
- /// Returns CATiledLayer as the backing layer.
34
- override class var layerClass: AnyClass {
35
- CATiledLayer.self
36
- }
90
+ override class var layerClass: AnyClass { CATiledLayer.self }
37
91
 
38
- /// Typed accessor for the tiled layer.
39
- private var tiledLayer: CATiledLayer {
40
- layer as! CATiledLayer
41
- }
92
+ private var tiledLayer: CATiledLayer { layer as! CATiledLayer }
93
+
94
+ private var _activePage: CGPDFPage?
95
+ private var _pdfKitDocument: PDFDocument?
96
+ private var _generation: UInt = 0
97
+ private let _cancelled = OSAtomicFlag()
42
98
 
43
99
  // MARK: - Initialization
44
100
 
@@ -52,7 +108,6 @@ final class TiledPDFPageView: UIView {
52
108
  commonInit()
53
109
  }
54
110
 
55
- /// Initializes with a specific configuration.
56
111
  convenience init(frame: CGRect, configuration: PDFConfiguration) {
57
112
  self.init(frame: frame)
58
113
  self.configuration = configuration
@@ -74,35 +129,139 @@ final class TiledPDFPageView: UIView {
74
129
  enableAntialiasing = configuration.enableAntialiasing
75
130
  }
76
131
 
132
+ // MARK: - Cancellation
133
+
134
+ func cancel() {
135
+ _cancelled.set()
136
+ }
137
+
138
+ private var currentCacheKey: String {
139
+ guard let url = pdfURL else { return "" }
140
+ return "\(url.absoluteString)_page\(pageIndex)"
141
+ }
142
+
143
+ // MARK: - Prepare Page (Flatten Pipeline)
144
+
145
+ func preparePage() {
146
+ _cancelled.reset()
147
+ _generation &+= 1
148
+ let currentGen = _generation
149
+
150
+ let cacheKey = currentCacheKey
151
+ if let cached = FlattenedPageCache.shared.entry(forKey: cacheKey) {
152
+ _activePage = cached.page
153
+ setNeedsDisplay()
154
+ return
155
+ }
156
+
157
+ _activePage = pdfPage
158
+
159
+ guard let url = pdfURL,
160
+ let originalPage = pdfPage else { return }
161
+
162
+ let idx = pageIndex
163
+ let originalCropBox = originalPage.getBoxRect(.cropBox)
164
+ let rotation = originalPage.rotationAngle
165
+
166
+ let pdfKitDoc: PDFDocument
167
+ if let existing = _pdfKitDocument {
168
+ pdfKitDoc = existing
169
+ } else if let newDoc = PDFDocument(url: url) {
170
+ _pdfKitDocument = newDoc
171
+ pdfKitDoc = newDoc
172
+ } else {
173
+ return
174
+ }
175
+
176
+ guard let pdfKitPage = pdfKitDoc.page(at: idx) else { return }
177
+ let annotations = pdfKitPage.annotations
178
+ if annotations.isEmpty { return }
179
+
180
+ DispatchQueue.global(qos: .userInitiated).async { [weak self] in
181
+ guard let self = self else { return }
182
+
183
+ let entry = Self.createFlattenedEntry(
184
+ pdfKitPage: pdfKitPage,
185
+ originalCropBox: originalCropBox,
186
+ rotation: Int(rotation)
187
+ )
188
+
189
+ guard let entry = entry else { return }
190
+ FlattenedPageCache.shared.setEntry(entry, forKey: cacheKey)
191
+
192
+ DispatchQueue.main.async { [weak self] in
193
+ guard let self = self, self._generation == currentGen else { return }
194
+ self._activePage = entry.page
195
+ self.setNeedsDisplay()
196
+ }
197
+ }
198
+ }
199
+
200
+ // MARK: - Flattening Logic
201
+ private static func createFlattenedEntry(
202
+ pdfKitPage: PDFPage,
203
+ originalCropBox: CGRect,
204
+ rotation: Int
205
+ ) -> FlattenedPageEntry? {
206
+ let finalSize: CGSize
207
+ if rotation == 90 || rotation == 270 {
208
+ finalSize = CGSize(width: originalCropBox.height, height: originalCropBox.width)
209
+ } else {
210
+ finalSize = originalCropBox.size
211
+ }
212
+
213
+ var mediaBox = CGRect(origin: .zero, size: finalSize)
214
+
215
+ let pdfData = NSMutableData()
216
+ guard let consumer = CGDataConsumer(data: pdfData as CFMutableData),
217
+ let pdfContext = CGContext(consumer: consumer, mediaBox: &mediaBox, nil) else {
218
+ return nil
219
+ }
220
+
221
+ pdfContext.beginPage(mediaBox: &mediaBox)
222
+
223
+ if originalCropBox.origin.x != 0 || originalCropBox.origin.y != 0 {
224
+ pdfContext.translateBy(x: -originalCropBox.origin.x, y: -originalCropBox.origin.y)
225
+ }
226
+
227
+ pdfKitPage.draw(with: .cropBox, to: pdfContext)
228
+
229
+ pdfContext.endPage()
230
+ pdfContext.closePDF()
231
+
232
+ guard let provider = CGDataProvider(data: pdfData as CFData),
233
+ let flattenedDoc = CGPDFDocument(provider),
234
+ let flattenedCGPage = flattenedDoc.page(at: 1) else {
235
+ return nil
236
+ }
237
+
238
+ return FlattenedPageEntry(document: flattenedDoc, page: flattenedCGPage)
239
+ }
240
+
77
241
  // MARK: - Rendering
78
242
 
79
243
  override func draw(_ rect: CGRect) {
244
+ guard !_cancelled.isSet() else { return }
245
+
80
246
  guard let context = UIGraphicsGetCurrentContext(),
81
- let page = pdfPage else {
82
- return
83
- }
247
+ let page = _activePage else { return }
84
248
 
85
249
  renderPage(page, in: context, rect: rect)
86
250
  }
87
251
 
88
- /// Renders the PDF page in the given graphics context.
89
252
  private func renderPage(_ page: CGPDFPage, in context: CGContext, rect: CGRect) {
90
253
  context.saveGState()
91
254
  defer { context.restoreGState() }
92
255
 
93
- // Configure rendering quality
94
256
  context.setShouldAntialias(enableAntialiasing)
95
257
  context.interpolationQuality = determineInterpolationQuality()
96
258
 
97
- // Fill background
98
259
  context.setFillColor(UIColor.white.cgColor)
99
260
  context.fill(rect)
100
261
 
101
- // Transform coordinate system (UIKit uses top-left origin, PDF uses bottom-left)
102
262
  context.translateBy(x: 0, y: bounds.height)
103
263
  context.scaleBy(x: 1.0, y: -1.0)
104
264
 
105
- // Apply PDF transform to fit the page
106
265
  let pdfTransform = page.getDrawingTransform(
107
266
  .cropBox,
108
267
  rect: bounds,
@@ -110,31 +269,11 @@ final class TiledPDFPageView: UIView {
110
269
  preserveAspectRatio: true
111
270
  )
112
271
  context.concatenate(pdfTransform)
113
-
114
272
  // Draw the page
115
273
  context.drawPDFPage(page)
116
274
  }
117
275
 
118
- /// Determines the interpolation quality based on zoom level.
119
276
  private func determineInterpolationQuality() -> CGInterpolationQuality {
120
277
  tiledLayer.levelsOfDetail == 1 ? .low : .high
121
278
  }
122
279
  }
123
-
124
- // MARK: - Public Methods
125
-
126
- extension TiledPDFPageView {
127
-
128
- /// Prepares the view for displaying a new page.
129
- func prepareForReuse() {
130
- pdfPage = nil
131
- layer.contents = nil
132
- }
133
-
134
- /// Updates the view size to match the page dimensions.
135
- func updateFrame(for page: CGPDFPage) {
136
- let pageRect = page.getBoxRect(.cropBox)
137
- frame = CGRect(origin: .zero, size: pageRect.size)
138
- pdfPage = page
139
- }
140
- }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "react-native-optimized-pdf",
3
- "version": "1.1.0",
4
- "description": "Ultra high-performance PDF viewer for React Native. Renders massive PDFs (1000+ pages) with extreme zoom levels while using minimal memory. 10x faster than native PDFKit on iOS, prevents crashes on large documents. Uses CATiledLayer (iOS) and PdfRenderer (Android) for tile-based rendering.",
3
+ "version": "1.3.1",
4
+ "description": "React Native PDF viewer with high performance, zoom, and support for large PDF files. Fast, memory-efficient, and supports annotations (annots) on iOS and Android.",
5
5
  "main": "index.ts",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1",
8
+ "test": "jest",
9
+ "test:coverage": "jest --coverage --coverageReporters=text",
9
10
  "lint": "eslint . --ext .ts,.tsx",
10
11
  "lint:fix": "eslint . --ext .ts,.tsx --fix",
11
12
  "format": "prettier --write \"**/*.{ts,tsx,js,json,md}\"",
@@ -14,21 +15,27 @@
14
15
  },
15
16
  "keywords": [
16
17
  "react-native",
18
+ "react-native-pdf",
17
19
  "pdf",
18
20
  "pdf-viewer",
19
- "viewer",
21
+ "react-native-pdf-viewer",
22
+ "pdf-reader",
23
+ "pdf-renderer",
24
+ "pdf-display",
20
25
  "ios",
21
26
  "android",
22
- "performance",
23
- "high-performance",
24
27
  "large-pdf",
28
+ "big-pdf",
29
+ "pdf-performance",
30
+ "fast-pdf",
25
31
  "memory-efficient",
26
32
  "tiled-rendering",
27
33
  "zoom",
28
- "catiled-layer",
29
- "pdfrenderer",
30
- "no-crash",
31
- "optimized"
34
+ "annotations",
35
+ "annots",
36
+ "pdfkit",
37
+ "pdfium",
38
+ "catiledlayer"
32
39
  ],
33
40
  "author": "Your Name",
34
41
  "license": "MIT",
@@ -38,16 +45,22 @@
38
45
  },
39
46
  "devDependencies": {
40
47
  "@react-native-community/eslint-config": "^3.2.0",
48
+ "@testing-library/react-native": "^13.3.1",
41
49
  "@types/crypto-js": "^4.2.2",
42
- "@types/react": "^18.0.0",
43
- "@types/react-native": "^0.72.0",
50
+ "@types/jest": "^29.5.14",
51
+ "@types/react": "^18.2.6",
52
+ "@types/react-native": "^0.64.19",
44
53
  "@typescript-eslint/eslint-plugin": "^6.0.0",
45
54
  "@typescript-eslint/parser": "^6.0.0",
46
55
  "eslint": "^8.0.0",
47
56
  "eslint-config-prettier": "^10.1.8",
48
57
  "eslint-plugin-jest": "^29.11.0",
49
58
  "eslint-plugin-prettier": "^5.5.4",
59
+ "jest": "^29.7.0",
50
60
  "prettier": "2.8.8",
61
+ "react": "18.2.0",
62
+ "react-native": "0.73.11",
63
+ "react-test-renderer": "18.2.0",
51
64
  "typescript": "^5.0.0"
52
65
  },
53
66
  "repository": {
@@ -55,7 +68,7 @@
55
68
  "url": "https://github.com/Herbeth-LKS/react-native-optimized-pdf"
56
69
  },
57
70
  "dependencies": {
58
- "crypto-js": "^4.2.0",
59
- "react-native-fs": "^2.20.0"
71
+ "@dr.pogodin/react-native-fs": "^2.41.0",
72
+ "crypto-js": "^4.2.0"
60
73
  }
61
74
  }