Skip to content

Commit 49ee454

Browse files
fix: re-measure web provider metrics when an ancestor scrolls
1 parent 9b7055e commit 49ee454

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

src/NativeSafeAreaProvider.web.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,20 @@ export function NativeSafeAreaProvider({
8888

8989
let resizeObserver: ResizeObserver | null = null;
9090
if (canMeasureProviderElement) {
91-
// Note this only observes size changes, position-only changes of the
92-
// provider element do not trigger an update.
9391
resizeObserver = new ResizeObserver(onEnd);
9492
resizeObserver.observe(providerElement);
93+
// Capture-phase listener so scrolling any ancestor re-measures the
94+
// provider element position.
95+
window.addEventListener('scroll', onEnd, true);
9596
}
9697

9798
return () => {
9899
document.body.removeChild(element);
99100
element.removeEventListener(getSupportedTransitionEvent(), onEnd);
100-
resizeObserver?.disconnect();
101+
if (resizeObserver != null) {
102+
resizeObserver.disconnect();
103+
window.removeEventListener('scroll', onEnd, true);
104+
}
101105
};
102106
}, [onInsetsChange]);
103107

src/__tests__/NativeSafeAreaProviderWeb-test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,26 @@ describe('NativeSafeAreaProvider.web', () => {
216216
});
217217
});
218218

219+
it('updates metrics when an ancestor scroll moves the provider element', () => {
220+
rectMock.mockReturnValue(makeRect(0, 100, 200, 300));
221+
const onInsetsChange = jest.fn<InsetChangeNativeCallback>();
222+
mountProvider(onInsetsChange);
223+
// Position-only change, the element moves up by 80px without resizing.
224+
rectMock.mockReturnValue(makeRect(0, 20, 200, 300));
225+
act(() => {
226+
document.dispatchEvent(new Event('scroll'));
227+
});
228+
expect(lastMetrics(onInsetsChange)).toEqual({
229+
insets: {
230+
top: WINDOW_INSETS.top - 20,
231+
bottom: 0,
232+
left: WINDOW_INSETS.left,
233+
right: 0,
234+
},
235+
frame: { x: 0, y: 20, width: 200, height: 300 },
236+
});
237+
});
238+
219239
it('falls back to window metrics when ResizeObserver is not available', () => {
220240
delete (globalThis as { ResizeObserver?: unknown }).ResizeObserver;
221241
rectMock.mockReturnValue(makeRect(20, 30, 200, 300));

0 commit comments

Comments
 (0)