@@ -14,9 +14,16 @@ type ScrollViewInstance = Exclude<
1414> ;
1515type ScrollViewRef = React . RefObject < ScrollViewInstance | null > ;
1616
17+ type EdgeInsets = { top : number ; right : number ; bottom : number ; left : number } ;
18+
1719export type PdfComponent = ( props : PdfViewProps ) => JSX . Element ;
1820
1921export type ZoomPdfViewProps = PdfViewProps & {
22+ /**
23+ * Content padding for safe area handling.
24+ */
25+ insets ?: EdgeInsets ;
26+
2027 /**
2128 * Callback when view starts to zoom.
2229 */
@@ -104,6 +111,7 @@ function useSyncAnimatedXY() {
104111function useZoomGesture (
105112 pdfSize : PageDim ,
106113 viewSize : PageDim ,
114+ insets : EdgeInsets | undefined ,
107115 resizeMode : ResizeMode | undefined ,
108116 maxScale : number ,
109117 hScrollRef : ScrollViewRef ,
@@ -119,6 +127,17 @@ function useZoomGesture(
119127
120128 const [ isZoomed , setIsZoomed ] = useState ( false ) ;
121129
130+ const innerViewSize = useMemo (
131+ ( ) =>
132+ insets == null
133+ ? viewSize
134+ : {
135+ width : viewSize . width - insets . left - insets . right ,
136+ height : viewSize . height - insets . top - insets . bottom ,
137+ } ,
138+ [ insets , viewSize ]
139+ ) ;
140+
122141 // Resolution to render.
123142 const containerScale = useRef ( {
124143 animated : new Animated . Value ( 1 ) ,
@@ -134,20 +153,20 @@ function useZoomGesture(
134153 useEffect ( ( ) => {
135154 const { viewWidth, viewHeight } = getViewDims (
136155 pdfSize ,
137- viewSize ,
156+ innerViewSize ,
138157 resizeMode
139158 ) ;
140159 const width = Math . max (
141- ( viewSize . width - containerScale . static * viewWidth ) / 2 ,
160+ ( innerViewSize . width - containerScale . static * viewWidth ) / 2 ,
142161 0
143162 ) ;
144163 const height = Math . max (
145- viewSize . height - containerScale . static * viewHeight ,
164+ innerViewSize . height - containerScale . static * viewHeight ,
146165 0
147166 ) ;
148167
149168 bufferSize . setValue ( { x : width , y : height } ) ;
150- } , [ bufferSize , containerScale , pdfSize , resizeMode , viewSize ] ) ;
169+ } , [ bufferSize , containerScale , innerViewSize , pdfSize , resizeMode ] ) ;
151170
152171 // Origin point of pinch gesture.
153172 const focalPoint = useSyncAnimatedXY ( ) ;
@@ -177,7 +196,10 @@ function useZoomGesture(
177196 return Gesture . Pinch ( )
178197 . runOnJS ( true )
179198 . onStart ( ( e ) =>
180- focalPoint . animated . setValue ( { x : e . focalX , y : e . focalY } )
199+ focalPoint . animated . setValue ( {
200+ x : e . focalX - ( insets ?. left ?? 0 ) ,
201+ y : e . focalY - ( insets ?. top ?? 0 ) ,
202+ } )
181203 )
182204 . onUpdate ( ( e ) => pinchScale . setValue ( e . scale ) )
183205 . onEnd ( ( e ) => {
@@ -188,12 +210,12 @@ function useZoomGesture(
188210 const applyScale = async ( ) => {
189211 const { viewWidth, viewHeight } = getViewDims (
190212 pdfSize ,
191- viewSize ,
213+ innerViewSize ,
192214 resizeMode
193215 ) ;
194216 const prevScale = containerScale . static ;
195217 const prevBufferX = Math . max (
196- ( viewSize . width - prevScale * viewWidth ) / 2 ,
218+ ( innerViewSize . width - prevScale * viewWidth ) / 2 ,
197219 0
198220 ) ;
199221
@@ -203,8 +225,8 @@ function useZoomGesture(
203225 containerScale . static = targetScale ;
204226 pinchScale . setValue ( 1 ) ;
205227 bufferSize . setValue ( {
206- x : Math . max ( ( viewSize . width - targetScale * viewWidth ) / 2 , 0 ) ,
207- y : Math . max ( viewSize . height - targetScale * viewHeight , 0 ) ,
228+ x : Math . max ( ( innerViewSize . width - targetScale * viewWidth ) / 2 , 0 ) ,
229+ y : Math . max ( innerViewSize . height - targetScale * viewHeight , 0 ) ,
208230 } ) ;
209231
210232 // Send zoom events.
@@ -261,6 +283,8 @@ function useZoomGesture(
261283 contentOffset ,
262284 focalPoint ,
263285 hScrollRef ,
286+ innerViewSize ,
287+ insets ,
264288 maxScale ,
265289 onZoomIn ,
266290 onZoomReset ,
@@ -269,13 +293,12 @@ function useZoomGesture(
269293 resizeMode ,
270294 setIsZoomed ,
271295 vScrollRef ,
272- viewSize ,
273296 ] ) ;
274297
275298 const zoomStyle : AnimatedStyle = useMemo ( ( ) => {
276299 const { viewWidth, viewHeight } = getViewDims (
277300 pdfSize ,
278- viewSize ,
301+ innerViewSize ,
279302 resizeMode
280303 ) ;
281304
@@ -315,10 +338,10 @@ function useZoomGesture(
315338 contentOffset ,
316339 containerScale ,
317340 focalPoint ,
341+ innerViewSize ,
318342 pdfSize ,
319343 resizeMode ,
320344 scale ,
321- viewSize ,
322345 ] ) ;
323346
324347 return {
@@ -335,6 +358,7 @@ function useZoomGesture(
335358 */
336359export function ZoomPdfView ( props : ZoomPdfViewProps ) {
337360 const {
361+ insets,
338362 maximumZoom,
339363 onLoadComplete,
340364 onZoomIn,
@@ -357,6 +381,7 @@ export function ZoomPdfView(props: ZoomPdfViewProps) {
357381 useZoomGesture (
358382 pdfSize ,
359383 viewSize ,
384+ insets ,
360385 resizeMode ,
361386 maximumZoom ?? 2 ,
362387 hScrollRef ,
@@ -436,6 +461,12 @@ export function ZoomPdfView(props: ZoomPdfViewProps) {
436461 >
437462 < GestureDetector gesture = { vScrollGesture } >
438463 < Animated . ScrollView
464+ contentContainerStyle = { {
465+ paddingTop : insets ?. top ,
466+ paddingBottom : insets ?. bottom ,
467+ paddingLeft : insets ?. left ,
468+ paddingRight : insets ?. right ,
469+ } }
439470 onScroll = { Animated . event (
440471 [
441472 {
0 commit comments