diff --git a/packages/web-api-hooks/src/useViewportScale.test.ts b/packages/web-api-hooks/src/useViewportScale.test.ts new file mode 100644 index 0000000..a3aaf51 --- /dev/null +++ b/packages/web-api-hooks/src/useViewportScale.test.ts @@ -0,0 +1,8 @@ +import { renderHook } from '@testing-library/react-hooks'; + +import { useViewportScale } from '.'; + +test('useViewportScale falls back to 1.0', () => { + const { result } = renderHook(() => useViewportScale()); + expect(result.current).toEqual(1.0); +}); diff --git a/packages/web-api-hooks/src/useViewportScale.ts b/packages/web-api-hooks/src/useViewportScale.ts index 796cc14..df09473 100644 --- a/packages/web-api-hooks/src/useViewportScale.ts +++ b/packages/web-api-hooks/src/useViewportScale.ts @@ -1,13 +1,13 @@ import { useEffect, useState } from 'react'; -import { canUseDOM, managedEventListener } from './utils'; +import { canUseVisualViewport, managedEventListener } from './utils'; /** * Tracks visual viewport scale. * * ⚗️ _The underlying technology is experimental. Please be aware about browser compatibility before using this in production._ * - * @returns Pinch-zoom scaling factor, falling back to `0` when unavailable. + * @returns Pinch-zoom scaling factor, falling back to `1.0` when unavailable. * * @example * function Component() { @@ -17,16 +17,18 @@ import { canUseDOM, managedEventListener } from './utils'; */ export default function useViewportScale(): number { const [scale, setScale] = useState( - canUseDOM ? window.visualViewport.scale : 0, + canUseVisualViewport ? window.visualViewport.scale : 1.0, ); - useEffect( - () => - managedEventListener(window.visualViewport, 'resize', () => { - setScale(window.visualViewport.scale); - }), - [], - ); + useEffect(() => { + if (!canUseVisualViewport) { + return; + } + + managedEventListener(window.visualViewport, 'resize', () => { + setScale(window.visualViewport.scale); + }); + }, []); return scale; } diff --git a/packages/web-api-hooks/src/useViewportScrollCoords.test.ts b/packages/web-api-hooks/src/useViewportScrollCoords.test.ts new file mode 100644 index 0000000..1e62f52 --- /dev/null +++ b/packages/web-api-hooks/src/useViewportScrollCoords.test.ts @@ -0,0 +1,8 @@ +import { renderHook } from '@testing-library/react-hooks'; + +import { useViewportScrollCoords } from '.'; + +test('useViewportScrollCoords falls back to [0, 0]', () => { + const { result } = renderHook(() => useViewportScrollCoords()); + expect(result.current).toEqual([0, 0]); +}); diff --git a/packages/web-api-hooks/src/useViewportScrollCoords.ts b/packages/web-api-hooks/src/useViewportScrollCoords.ts index 8ad83a7..12c42ec 100644 --- a/packages/web-api-hooks/src/useViewportScrollCoords.ts +++ b/packages/web-api-hooks/src/useViewportScrollCoords.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { canUseDOM, managedEventListener } from './utils'; +import { canUseVisualViewport, managedEventListener } from './utils'; /** * Tracks visual viewport scroll position. @@ -17,21 +17,26 @@ import { canUseDOM, managedEventListener } from './utils'; */ export default function useViewportScrollCoords(): Readonly<[number, number]> { const [coords, setCoords] = useState>( - canUseDOM + canUseVisualViewport ? [window.visualViewport.pageLeft, window.visualViewport.pageTop] : [0, 0], ); - useEffect( - () => - managedEventListener(window.visualViewport, 'scroll', () => { - setCoords([ - window.visualViewport.pageLeft, - window.visualViewport.pageTop, - ]); - }), - [], - ); + useEffect(() => { + if (!canUseVisualViewport) { + return; + } + + function handler(): void { + setCoords([ + window.visualViewport.pageLeft, + window.visualViewport.pageTop, + ]); + } + + managedEventListener(window?.visualViewport, 'scroll', handler); + managedEventListener(window?.visualViewport, 'resize', handler); + }, []); return coords; } diff --git a/packages/web-api-hooks/src/utils.ts b/packages/web-api-hooks/src/utils.ts index 60e8813..3f2a30e 100644 --- a/packages/web-api-hooks/src/utils.ts +++ b/packages/web-api-hooks/src/utils.ts @@ -4,6 +4,8 @@ import { EventMap } from './types'; export const canUseDOM = typeof window !== 'undefined'; +export const canUseVisualViewport = canUseDOM && 'visualViewport' in window; + export function dethunkify(value: T | (() => T)): T { return typeof value === 'function' ? (value as () => T)() : value; }