@june24/expo-pdf-reader 0.1.3 → 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.
|
@@ -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"]}
|
|
@@ -23,6 +23,9 @@ class ExpoPdfReaderView: ExpoView, UIGestureRecognizerDelegate {
|
|
|
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] = []
|
|
@@ -501,6 +504,7 @@ class ExpoPdfReaderView: ExpoView, UIGestureRecognizerDelegate {
|
|
|
501
504
|
guard let page = pdfView.currentPage else { return }
|
|
502
505
|
let location = gesture.location(in: pdfView)
|
|
503
506
|
let convertedPoint = pdfView.convert(location, to: page)
|
|
507
|
+
let viewLocation = location // Keep view coordinates for drawing layer
|
|
504
508
|
|
|
505
509
|
// Handle eraser
|
|
506
510
|
if currentTool == "eraser" {
|
|
@@ -552,38 +556,99 @@ class ExpoPdfReaderView: ExpoView, UIGestureRecognizerDelegate {
|
|
|
552
556
|
switch gesture.state {
|
|
553
557
|
case .began:
|
|
554
558
|
currentPath = UIBezierPath()
|
|
555
|
-
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
|
+
}
|
|
569
|
+
|
|
570
|
+
case .changed:
|
|
571
|
+
guard let path = currentPath else { return }
|
|
572
|
+
path.addLine(to: viewLocation) // Use view coordinates for drawing layer
|
|
573
|
+
|
|
574
|
+
// Update drawing layer to show live preview
|
|
575
|
+
drawingLayer?.path = path.cgPath
|
|
576
|
+
if currentTool == "pen" {
|
|
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
|
|
556
593
|
|
|
557
|
-
//
|
|
558
|
-
let
|
|
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)
|
|
559
626
|
|
|
560
627
|
if currentTool == "pen" {
|
|
561
|
-
let annotation = PDFAnnotation(bounds:
|
|
628
|
+
let annotation = PDFAnnotation(bounds: pathBounds, forType: .ink, withProperties: nil)
|
|
562
629
|
annotation.color = currentColor
|
|
563
630
|
let border = PDFBorder()
|
|
564
631
|
border.lineWidth = currentStrokeWidth
|
|
565
632
|
annotation.border = border
|
|
566
|
-
annotation.add(
|
|
633
|
+
annotation.add(pagePathForAnnotation)
|
|
567
634
|
page.addAnnotation(annotation)
|
|
568
|
-
|
|
635
|
+
|
|
636
|
+
// Force PDF view to update
|
|
637
|
+
pdfView.setNeedsDisplay()
|
|
569
638
|
}
|
|
570
639
|
else if currentTool == "highlighter" {
|
|
571
|
-
let annotation = PDFAnnotation(bounds:
|
|
640
|
+
let annotation = PDFAnnotation(bounds: pathBounds, forType: .ink, withProperties: nil)
|
|
572
641
|
annotation.color = currentColor.withAlphaComponent(0.3)
|
|
573
642
|
let border = PDFBorder()
|
|
574
643
|
border.lineWidth = currentStrokeWidth * 3.0
|
|
575
644
|
annotation.border = border
|
|
576
|
-
annotation.add(
|
|
645
|
+
annotation.add(pagePathForAnnotation)
|
|
577
646
|
page.addAnnotation(annotation)
|
|
578
|
-
|
|
647
|
+
|
|
648
|
+
// Force PDF view to update
|
|
649
|
+
pdfView.setNeedsDisplay()
|
|
579
650
|
}
|
|
580
651
|
|
|
581
|
-
case .changed:
|
|
582
|
-
guard let path = currentPath, let annotation = currentAnnotation else { return }
|
|
583
|
-
path.addLine(to: convertedPoint)
|
|
584
|
-
annotation.add(path) // Update path
|
|
585
|
-
|
|
586
|
-
case .ended, .cancelled:
|
|
587
652
|
// Clear redo stack when new annotation is added
|
|
588
653
|
redoStack.removeAll()
|
|
589
654
|
|
|
@@ -595,6 +660,13 @@ class ExpoPdfReaderView: ExpoView, UIGestureRecognizerDelegate {
|
|
|
595
660
|
"annotations": getAnnotations()
|
|
596
661
|
])
|
|
597
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
|
+
|
|
598
670
|
default:
|
|
599
671
|
break
|
|
600
672
|
}
|
package/package.json
CHANGED