Skip to content

Commit

Permalink
feat: convert useWindowSize to useViewportSize
Browse files Browse the repository at this point in the history
  • Loading branch information
thebuilder committed Jul 30, 2024
1 parent 0183c78 commit b5b4c55
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 48 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,16 @@ if (status === "ready") {
}
```

### `useWindowSize`
### `useViewportSize`

Get the current window size. If the window resizes, the hook will update the size.
Get the current viewport size. If the viewport resizes, the hook will update the size.
This will prefer the [visual viewport](https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport)
size if available, otherwise it will use the window size.

```ts
import { useWindowSize } from "@charlietango/hooks/use-window-size";
import { useViewportSize } from "@charlietango/hooks/use-viewport-size";

const { width, height } = useWindowSize();
const { width, height } = useViewportSize();
```

<!-- Badges -->
Expand Down
33 changes: 33 additions & 0 deletions src/__tests__/useViewportSize.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { act, renderHook } from "@testing-library/react";
import { page } from "@vitest/browser/context";
import { useViewportSize } from "../hooks/useViewportSize";

test("get viewport size", async () => {
await page.viewport(800, 600);
const { result } = renderHook(useViewportSize);
expect(result.current).toEqual({ width: 800, height: 600 });

// Should observe the new viewport size on `resize`
await page.viewport(1024, 768);

act(() => {
window.visualViewport?.dispatchEvent(new Event("resize"));
});
expect(result.current).toEqual({ width: 1024, height: 768 });
});

test("fallback to window size", async () => {
await page.viewport(800, 600);
// Remove `visualViewport` to test the fallback to `window.innerWidth` and `window.innerHeight` values
window.visualViewport = null;
const { result } = renderHook(useViewportSize);
expect(result.current).toEqual({ width: 800, height: 600 });

// Should observe the new viewport size on `resize`
await page.viewport(1024, 768);

act(() => {
window.dispatchEvent(new Event("resize"));
});
expect(result.current).toEqual({ width: 1024, height: 768 });
});
17 changes: 0 additions & 17 deletions src/__tests__/useWindowSize.test.tsx

This file was deleted.

32 changes: 32 additions & 0 deletions src/hooks/useViewportSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useSyncExternalStore } from "react";

const subscribe = (callback: () => void) => {
const viewport = window.visualViewport || window;
viewport.addEventListener("resize", callback);
return () => {
viewport.removeEventListener("resize", callback);
};
};

const getSnapshot = () => {
return JSON.stringify({
width: window.visualViewport?.width ?? window.innerWidth,
height: window.visualViewport?.height ?? window.innerHeight,
});
};
const getServerSnapshot = () => JSON.stringify({ width: 0, height: 0 });

/**
* Get the current viewport size. If the viewport resizes, the hook will update the size.
* This will prefer the [visual viewport](https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport) size if available, otherwise it will use the window size.
*
*
* ```tsx
* const { width, height } = useViewportSize();
* ```
*/
export function useViewportSize() {
return JSON.parse(
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot),
) as { width: number; height: number };
}
27 changes: 0 additions & 27 deletions src/hooks/useWindowSize.ts

This file was deleted.

0 comments on commit b5b4c55

Please sign in to comment.