Skip to content

Commit 719e912

Browse files
committed
feat(zoom): accept insets for safe area support
1 parent f6329c7 commit 719e912

2 files changed

Lines changed: 45 additions & 12 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ display mode.
126126

127127
Props:
128128
- All props from `PdfView`
129+
- `insets: { top: number; right: number; bottom: number; left: number }`
130+
- Optional: Content padding for safe area handling.
129131
- `onZoomIn: () => void`
130132
- Optional: Callback when view starts to zoom.
131133
- `onZoomReset: () => void`

src/ZoomPdfView.tsx

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,16 @@ type ScrollViewInstance = Exclude<
1414
>;
1515
type ScrollViewRef = React.RefObject<ScrollViewInstance | null>;
1616

17+
type EdgeInsets = { top: number; right: number; bottom: number; left: number };
18+
1719
export type PdfComponent = (props: PdfViewProps) => JSX.Element;
1820

1921
export 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() {
104111
function 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
*/
336359
export 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

Comments
 (0)