@june24/expo-pdf-reader 0.1.2 → 0.1.4
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/build/ExpoPdfReader.types.js.map +1 -1
- package/build/index.d.ts +3 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/ios/ExpoPdfReaderView.swift +101 -20
- package/package.json +2 -2
- package/src/ExpoPdfReader.types.ts +1 -1
- package/src/index.ts +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoPdfReader.types.js","sourceRoot":"","sources":["../src/ExpoPdfReader.types.ts"],"names":[],"mappings":"","sourcesContent":["import { ViewProps, StyleProp, ViewStyle } from 'react-native';\n\nexport type AnnotationTool = 'none' | 'pen' | 'highlighter' | 'text' | 'note' | 'eraser';\n\nexport type DisplayMode = 'single' | 'continuous' | 'twoUp' | 'twoUpContinuous';\n\nexport type Point = { x: number; y: number };\n\nexport type Annotation = {\n type: 'pen' | 'highlighter' | 'text';\n color: string;\n page?: number;\n points?: Point[][]; // For pen/highlighter\n width?: number; // Stroke width or font size for text? Let's use fontSize for text explicitly\n text?: string; // For text\n fontSize?: number; // For text\n x?: number; // For text\n y?: number; // For text\n};\n\nexport type AnnotationChangeEvent = {\n nativeEvent: {\n annotations: Annotation[];\n };\n};\n\nexport type PageChangeEvent = {\n nativeEvent: {\n page: number;\n total: number;\n };\n};\n\nexport type ScrollEvent = {\n nativeEvent: {\n x: number;\n y: number;\n contentWidth: number;\n contentHeight: number;\n layoutWidth: number;\n layoutHeight: number;\n };\n};\n\nexport type SearchResult = {\n page: number;\n x: number;\n y: number;\n width: number;\n height: number;\n textSnippet?: string;\n};\n\n// Public API: group drawing configuration into a single object\nexport type AnnotationOptions = {\n tool?: AnnotationTool;\n color?: string; // Hex color\n fontSize?: number;\n text?: string;\n strokeWidth?: number; // line thickness for pen/highlighter\n};\n\n// Props exposed to JS users of the component\nexport type ExpoPdfReaderViewProps = ViewProps & {\n url: string;\n style?: StyleProp<ViewStyle>;\n displayMode?: DisplayMode; // 'single' | 'continuous' | 'twoUp' | 'twoUpContinuous'\n initialPage?: number; // starting page index (0-based)\n minZoom?: number;\n maxZoom?: number;\n annotationOptions?: AnnotationOptions;\n initialAnnotations?: Annotation[];\n onAnnotationChange?: (event: AnnotationChangeEvent) => void;\n onPageChange?: (event: PageChangeEvent) => void;\n onScroll?: (event: ScrollEvent) => void;\n};\n\n// Internal props that the native view actually receives.\n// This keeps backwards-compat with the native module while giving\n// JS a cleaner grouped API via `annotationOptions`.\nexport type NativeExpoPdfReaderViewProps = ViewProps & {\n url: string;\n style?: StyleProp<ViewStyle>;\n displayMode?: DisplayMode;\n initialPage?: number;\n minZoom?: number;\n maxZoom?: number;\n annotationTool?: AnnotationTool;\n annotationColor?: string; // Hex color\n annotationFontSize?: number;\n annotationText?: string; // Default text to place\n
|
|
1
|
+
{"version":3,"file":"ExpoPdfReader.types.js","sourceRoot":"","sources":["../src/ExpoPdfReader.types.ts"],"names":[],"mappings":"","sourcesContent":["import { ViewProps, StyleProp, ViewStyle } from 'react-native';\n\nexport type AnnotationTool = 'none' | 'pen' | 'highlighter' | 'text' | 'note' | 'eraser';\n\nexport type DisplayMode = 'single' | 'continuous' | 'twoUp' | 'twoUpContinuous';\n\nexport type Point = { x: number; y: number };\n\nexport type Annotation = {\n type: 'pen' | 'highlighter' | 'text';\n color: string;\n page?: number;\n points?: Point[][]; // For pen/highlighter\n width?: number; // Stroke width or font size for text? Let's use fontSize for text explicitly\n text?: string; // For text\n fontSize?: number; // For text\n x?: number; // For text\n y?: number; // For text\n};\n\nexport type AnnotationChangeEvent = {\n nativeEvent: {\n annotations: Annotation[];\n };\n};\n\nexport type PageChangeEvent = {\n nativeEvent: {\n page: number;\n total: number;\n };\n};\n\nexport type ScrollEvent = {\n nativeEvent: {\n x: number;\n y: number;\n contentWidth: number;\n contentHeight: number;\n layoutWidth: number;\n layoutHeight: number;\n };\n};\n\nexport type SearchResult = {\n page: number;\n x: number;\n y: number;\n width: number;\n height: number;\n textSnippet?: string;\n};\n\n// Public API: group drawing configuration into a single object\nexport type AnnotationOptions = {\n tool?: AnnotationTool;\n color?: string; // Hex color\n fontSize?: number;\n text?: string;\n strokeWidth?: number; // line thickness for pen/highlighter\n};\n\n// Props exposed to JS users of the component\nexport type ExpoPdfReaderViewProps = ViewProps & {\n url: string;\n style?: StyleProp<ViewStyle>;\n displayMode?: DisplayMode; // 'single' | 'continuous' | 'twoUp' | 'twoUpContinuous'\n initialPage?: number; // starting page index (0-based)\n minZoom?: number;\n maxZoom?: number;\n annotationOptions?: AnnotationOptions;\n initialAnnotations?: Annotation[];\n onAnnotationChange?: (event: AnnotationChangeEvent) => void;\n onPageChange?: (event: PageChangeEvent) => void;\n onScroll?: (event: ScrollEvent) => void;\n};\n\n// Internal props that the native view actually receives.\n// This keeps backwards-compat with the native module while giving\n// JS a cleaner grouped API via `annotationOptions`.\nexport type NativeExpoPdfReaderViewProps = ViewProps & {\n url: string;\n style?: StyleProp<ViewStyle>;\n displayMode?: DisplayMode;\n initialPage?: number;\n minZoom?: number;\n maxZoom?: number;\n annotationTool?: AnnotationTool;\n annotationColor?: string; // Hex color\n annotationFontSize?: number;\n annotationText?: string; // Default text to place\n // Native-only props derived from AnnotationOptions\n annotationStrokeWidth?: number;\n initialAnnotations?: Annotation[];\n onAnnotationChange?: (event: AnnotationChangeEvent) => void;\n onPageChange?: (event: PageChangeEvent) => void;\n onScroll?: (event: ScrollEvent) => void;\n};\n\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ExpoPdfReaderView from './ExpoPdfReaderView';
|
|
2
|
-
import { ExpoPdfReaderViewProps } from './ExpoPdfReader.types';
|
|
3
|
-
export { ExpoPdfReaderView, ExpoPdfReaderViewProps };
|
|
1
|
+
import ExpoPdfReaderView, { ExpoPdfReaderRef } from './ExpoPdfReaderView';
|
|
2
|
+
import { ExpoPdfReaderViewProps, Annotation, AnnotationOptions, AnnotationTool, AnnotationChangeEvent, PageChangeEvent, ScrollEvent, SearchResult, DisplayMode } from './ExpoPdfReader.types';
|
|
3
|
+
export { ExpoPdfReaderView, ExpoPdfReaderRef, ExpoPdfReaderViewProps, Annotation, AnnotationOptions, AnnotationTool, AnnotationChangeEvent, PageChangeEvent, ScrollEvent, SearchResult, DisplayMode, };
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,EAAE,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAG,MAAM,uBAAuB,CAAC;AAE/L,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,GAAG,CAAC"}
|
package/build/index.js
CHANGED
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAuC,MAAM,qBAAqB,CAAC;AAG1E,OAAO,EAAE,iBAAiB,GAA4K,CAAC","sourcesContent":["import ExpoPdfReaderView, { ExpoPdfReaderRef } from './ExpoPdfReaderView';\nimport { ExpoPdfReaderViewProps, Annotation, AnnotationOptions, AnnotationTool, AnnotationChangeEvent, PageChangeEvent, ScrollEvent, SearchResult, DisplayMode, } from './ExpoPdfReader.types';\n\nexport { ExpoPdfReaderView, ExpoPdfReaderRef, ExpoPdfReaderViewProps, Annotation, AnnotationOptions, AnnotationTool, AnnotationChangeEvent, PageChangeEvent, ScrollEvent, SearchResult, DisplayMode, };\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ExpoModulesCore
|
|
2
2
|
import PDFKit
|
|
3
3
|
|
|
4
|
-
class ExpoPdfReaderView: ExpoView {
|
|
4
|
+
class ExpoPdfReaderView: ExpoView, UIGestureRecognizerDelegate {
|
|
5
5
|
let pdfView = PDFView()
|
|
6
6
|
var currentTool: String = "none"
|
|
7
7
|
var currentColor: UIColor = .black
|
|
@@ -23,6 +23,9 @@ class ExpoPdfReaderView: ExpoView {
|
|
|
23
23
|
private var currentAnnotation: PDFAnnotation?
|
|
24
24
|
private var currentPath: UIBezierPath?
|
|
25
25
|
|
|
26
|
+
// Drawing overlay layer for live preview
|
|
27
|
+
private var drawingLayer: CAShapeLayer?
|
|
28
|
+
|
|
26
29
|
// Undo/Redo stacks
|
|
27
30
|
private var undoStack: [PDFAnnotation] = []
|
|
28
31
|
private var redoStack: [PDFAnnotation] = []
|
|
@@ -40,7 +43,9 @@ class ExpoPdfReaderView: ExpoView {
|
|
|
40
43
|
|
|
41
44
|
// Setup gestures
|
|
42
45
|
panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
|
|
46
|
+
panGesture?.delegate = self
|
|
43
47
|
tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
|
|
48
|
+
tapGesture?.delegate = self
|
|
44
49
|
|
|
45
50
|
// Initially disabled
|
|
46
51
|
panGesture?.isEnabled = false
|
|
@@ -195,11 +200,18 @@ class ExpoPdfReaderView: ExpoView {
|
|
|
195
200
|
let isDrawing = tool == "pen" || tool == "highlighter"
|
|
196
201
|
let isEraser = tool == "eraser"
|
|
197
202
|
panGesture?.isEnabled = isDrawing || isEraser
|
|
198
|
-
pdfView.isUserInteractionEnabled = !isDrawing && !isEraser // Disable PDF interaction when drawing/erasing to prevent scrolling
|
|
199
203
|
|
|
200
|
-
//
|
|
201
|
-
if
|
|
202
|
-
|
|
204
|
+
// Disable PDF's built-in gestures when drawing/erasing
|
|
205
|
+
if isDrawing || isEraser {
|
|
206
|
+
// Disable scroll and other PDF interactions
|
|
207
|
+
if let scrollView = pdfView.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView {
|
|
208
|
+
scrollView.isScrollEnabled = false
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
// Re-enable scrolling
|
|
212
|
+
if let scrollView = pdfView.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView {
|
|
213
|
+
scrollView.isScrollEnabled = true
|
|
214
|
+
}
|
|
203
215
|
}
|
|
204
216
|
|
|
205
217
|
if tool == "text" || tool == "note" {
|
|
@@ -492,6 +504,7 @@ class ExpoPdfReaderView: ExpoView {
|
|
|
492
504
|
guard let page = pdfView.currentPage else { return }
|
|
493
505
|
let location = gesture.location(in: pdfView)
|
|
494
506
|
let convertedPoint = pdfView.convert(location, to: page)
|
|
507
|
+
let viewLocation = location // Keep view coordinates for drawing layer
|
|
495
508
|
|
|
496
509
|
// Handle eraser
|
|
497
510
|
if currentTool == "eraser" {
|
|
@@ -543,38 +556,99 @@ class ExpoPdfReaderView: ExpoView {
|
|
|
543
556
|
switch gesture.state {
|
|
544
557
|
case .began:
|
|
545
558
|
currentPath = UIBezierPath()
|
|
546
|
-
currentPath?.move(to:
|
|
559
|
+
currentPath?.move(to: viewLocation) // Use view coordinates for drawing layer
|
|
560
|
+
|
|
561
|
+
// Create drawing layer for live preview in view coordinates
|
|
562
|
+
if drawingLayer == nil {
|
|
563
|
+
drawingLayer = CAShapeLayer()
|
|
564
|
+
drawingLayer?.fillColor = UIColor.clear.cgColor
|
|
565
|
+
drawingLayer?.lineCap = .round
|
|
566
|
+
drawingLayer?.lineJoin = .round
|
|
567
|
+
pdfView.layer.addSublayer(drawingLayer!)
|
|
568
|
+
}
|
|
547
569
|
|
|
548
|
-
|
|
549
|
-
let
|
|
570
|
+
case .changed:
|
|
571
|
+
guard let path = currentPath else { return }
|
|
572
|
+
path.addLine(to: viewLocation) // Use view coordinates for drawing layer
|
|
550
573
|
|
|
574
|
+
// Update drawing layer to show live preview
|
|
575
|
+
drawingLayer?.path = path.cgPath
|
|
551
576
|
if currentTool == "pen" {
|
|
552
|
-
|
|
577
|
+
drawingLayer?.strokeColor = currentColor.cgColor
|
|
578
|
+
drawingLayer?.lineWidth = currentStrokeWidth
|
|
579
|
+
drawingLayer?.opacity = 1.0
|
|
580
|
+
} else if currentTool == "highlighter" {
|
|
581
|
+
drawingLayer?.strokeColor = currentColor.cgColor
|
|
582
|
+
drawingLayer?.lineWidth = currentStrokeWidth * 3.0
|
|
583
|
+
drawingLayer?.opacity = 0.3
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
case .ended:
|
|
587
|
+
guard let viewPath = currentPath else { return }
|
|
588
|
+
viewPath.addLine(to: viewLocation) // Complete view path
|
|
589
|
+
|
|
590
|
+
// Remove drawing layer
|
|
591
|
+
drawingLayer?.removeFromSuperlayer()
|
|
592
|
+
drawingLayer = nil
|
|
593
|
+
|
|
594
|
+
// Convert view path to page coordinates
|
|
595
|
+
let pagePathForAnnotation = UIBezierPath()
|
|
596
|
+
viewPath.cgPath.applyWithBlock { element in
|
|
597
|
+
let points = element.pointee.points
|
|
598
|
+
switch element.pointee.type {
|
|
599
|
+
case .moveToPoint:
|
|
600
|
+
let pagePoint = self.pdfView.convert(points[0], to: page)
|
|
601
|
+
pagePathForAnnotation.move(to: pagePoint)
|
|
602
|
+
case .addLineToPoint:
|
|
603
|
+
let pagePoint = self.pdfView.convert(points[0], to: page)
|
|
604
|
+
pagePathForAnnotation.addLine(to: pagePoint)
|
|
605
|
+
case .addQuadCurveToPoint:
|
|
606
|
+
let cp = self.pdfView.convert(points[0], to: page)
|
|
607
|
+
let pt = self.pdfView.convert(points[1], to: page)
|
|
608
|
+
pagePathForAnnotation.addQuadCurve(to: pt, controlPoint: cp)
|
|
609
|
+
case .addCurveToPoint:
|
|
610
|
+
let cp1 = self.pdfView.convert(points[0], to: page)
|
|
611
|
+
let cp2 = self.pdfView.convert(points[1], to: page)
|
|
612
|
+
let pt = self.pdfView.convert(points[2], to: page)
|
|
613
|
+
pagePathForAnnotation.addCurve(to: pt, controlPoint1: cp1, controlPoint2: cp2)
|
|
614
|
+
case .closeSubpath:
|
|
615
|
+
pagePathForAnnotation.close()
|
|
616
|
+
@unknown default:
|
|
617
|
+
break
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Calculate proper bounds from path
|
|
622
|
+
var pathBounds = pagePathForAnnotation.bounds
|
|
623
|
+
// Expand bounds slightly to accommodate stroke width
|
|
624
|
+
let expansion = max(currentStrokeWidth * 2, 20)
|
|
625
|
+
pathBounds = pathBounds.insetBy(dx: -expansion, dy: -expansion)
|
|
626
|
+
|
|
627
|
+
if currentTool == "pen" {
|
|
628
|
+
let annotation = PDFAnnotation(bounds: pathBounds, forType: .ink, withProperties: nil)
|
|
553
629
|
annotation.color = currentColor
|
|
554
630
|
let border = PDFBorder()
|
|
555
631
|
border.lineWidth = currentStrokeWidth
|
|
556
632
|
annotation.border = border
|
|
557
|
-
annotation.add(
|
|
633
|
+
annotation.add(pagePathForAnnotation)
|
|
558
634
|
page.addAnnotation(annotation)
|
|
559
|
-
|
|
635
|
+
|
|
636
|
+
// Force PDF view to update
|
|
637
|
+
pdfView.setNeedsDisplay()
|
|
560
638
|
}
|
|
561
639
|
else if currentTool == "highlighter" {
|
|
562
|
-
let annotation = PDFAnnotation(bounds:
|
|
640
|
+
let annotation = PDFAnnotation(bounds: pathBounds, forType: .ink, withProperties: nil)
|
|
563
641
|
annotation.color = currentColor.withAlphaComponent(0.3)
|
|
564
642
|
let border = PDFBorder()
|
|
565
643
|
border.lineWidth = currentStrokeWidth * 3.0
|
|
566
644
|
annotation.border = border
|
|
567
|
-
annotation.add(
|
|
645
|
+
annotation.add(pagePathForAnnotation)
|
|
568
646
|
page.addAnnotation(annotation)
|
|
569
|
-
|
|
647
|
+
|
|
648
|
+
// Force PDF view to update
|
|
649
|
+
pdfView.setNeedsDisplay()
|
|
570
650
|
}
|
|
571
651
|
|
|
572
|
-
case .changed:
|
|
573
|
-
guard let path = currentPath, let annotation = currentAnnotation else { return }
|
|
574
|
-
path.addLine(to: convertedPoint)
|
|
575
|
-
annotation.add(path) // Update path
|
|
576
|
-
|
|
577
|
-
case .ended, .cancelled:
|
|
578
652
|
// Clear redo stack when new annotation is added
|
|
579
653
|
redoStack.removeAll()
|
|
580
654
|
|
|
@@ -586,6 +660,13 @@ class ExpoPdfReaderView: ExpoView {
|
|
|
586
660
|
"annotations": getAnnotations()
|
|
587
661
|
])
|
|
588
662
|
|
|
663
|
+
case .cancelled:
|
|
664
|
+
// Remove drawing layer and clear without adding annotation
|
|
665
|
+
drawingLayer?.removeFromSuperlayer()
|
|
666
|
+
drawingLayer = nil
|
|
667
|
+
currentPath = nil
|
|
668
|
+
currentAnnotation = nil
|
|
669
|
+
|
|
589
670
|
default:
|
|
590
671
|
break
|
|
591
672
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@june24/expo-pdf-reader",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "A PDF reader for Expo apps with annotation and zoom controls",
|
|
5
5
|
"homepage": "git@gitlab.com:june_241/expo-pdf-reader.git",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"author": "User",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"expo-modules-core": "^
|
|
25
|
+
"expo-modules-core": "^3.0.29"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"expo-module-scripts": "^5.0.8",
|
|
@@ -89,7 +89,7 @@ export type NativeExpoPdfReaderViewProps = ViewProps & {
|
|
|
89
89
|
annotationColor?: string; // Hex color
|
|
90
90
|
annotationFontSize?: number;
|
|
91
91
|
annotationText?: string; // Default text to place
|
|
92
|
-
|
|
92
|
+
// Native-only props derived from AnnotationOptions
|
|
93
93
|
annotationStrokeWidth?: number;
|
|
94
94
|
initialAnnotations?: Annotation[];
|
|
95
95
|
onAnnotationChange?: (event: AnnotationChangeEvent) => void;
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ExpoPdfReaderView from './ExpoPdfReaderView';
|
|
2
|
-
import { ExpoPdfReaderViewProps } from './ExpoPdfReader.types';
|
|
1
|
+
import ExpoPdfReaderView, { ExpoPdfReaderRef } from './ExpoPdfReaderView';
|
|
2
|
+
import { ExpoPdfReaderViewProps, Annotation, AnnotationOptions, AnnotationTool, AnnotationChangeEvent, PageChangeEvent, ScrollEvent, SearchResult, DisplayMode, } from './ExpoPdfReader.types';
|
|
3
3
|
|
|
4
|
-
export { ExpoPdfReaderView, ExpoPdfReaderViewProps };
|
|
4
|
+
export { ExpoPdfReaderView, ExpoPdfReaderRef, ExpoPdfReaderViewProps, Annotation, AnnotationOptions, AnnotationTool, AnnotationChangeEvent, PageChangeEvent, ScrollEvent, SearchResult, DisplayMode, };
|