Skip to content

Commit

Permalink
feat: update useEventListener Options (#81)
Browse files Browse the repository at this point in the history
Move the target parameter to the bind options and set default to window in useEventListener hook
  • Loading branch information
immois authored Dec 13, 2023
1 parent 88b7e0d commit df1362f
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 40 deletions.
6 changes: 6 additions & 0 deletions .changeset/five-rocks-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@raddix/use-scroll-position': minor
'@raddix/use-window-size': minor
---

update the useEventListener hook with the new options
5 changes: 5 additions & 0 deletions .changeset/gentle-terms-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@raddix/use-event-listener': major
---

Move the target parameter to the bind options and set default to window
9 changes: 4 additions & 5 deletions packages/hooks/use-event-listener/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { type RefObject, useEffect, useRef } from 'react';

export const _window = typeof window !== 'undefined' ? window : null;
export const _document = typeof document !== 'undefined' ? document : null;
interface Options extends AddEventListenerOptions {
target?: RefObject<EventTarget> | EventTarget;
}

export const useEventListener = <T extends keyof HTMLElementEventMap>(
target: RefObject<EventTarget> | EventTarget | null,
eventType: T,
callback: (event: HTMLElementEventMap[T]) => void,
options?: boolean | AddEventListenerOptions
{ target = globalThis, ...options }: Options = {}
): void => {
const savedCallback = useRef(callback);

Expand All @@ -16,7 +16,6 @@ export const useEventListener = <T extends keyof HTMLElementEventMap>(
}, [callback]);

useEffect(() => {
if (target === null) return;
const targetElement = 'current' in target ? target.current : target;

if (!targetElement?.addEventListener) return;
Expand Down
12 changes: 5 additions & 7 deletions packages/hooks/use-event-listener/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ describe('useEventListener test:', () => {
jest.clearAllMocks();
});

it('should add event listener in document', () => {
it('should add event listener in window', () => {
const callback = jest.fn();
const { unmount } = renderHook(() =>
useEventListener(document, 'click', callback)
);
const { unmount } = renderHook(() => useEventListener('click', callback));

expect(callback).not.toHaveBeenCalled();

Expand All @@ -40,7 +38,7 @@ describe('useEventListener test:', () => {
it('should add event listener in element', () => {
const callback = jest.fn();
const { unmount } = renderHook(() =>
useEventListener(container, 'click', callback)
useEventListener('click', callback, { target: container })
);

expect(callback).not.toHaveBeenCalled();
Expand All @@ -63,7 +61,7 @@ describe('useEventListener test:', () => {
it('should add event listener to ref', () => {
const callback = jest.fn();
const ref = { current: container };
renderHook(() => useEventListener(ref, 'click', callback));
renderHook(() => useEventListener('click', callback, { target: ref }));

act(() => {
document.body.click();
Expand All @@ -81,7 +79,7 @@ describe('useEventListener test:', () => {
it('should not add event listener if the target does not have addEventListener', () => {
const callback = jest.fn();
const ref = { current: null };
renderHook(() => useEventListener(ref, 'click', callback));
renderHook(() => useEventListener('click', callback, { target: ref }));

act(() => {
document.body.click();
Expand Down
11 changes: 5 additions & 6 deletions packages/hooks/use-scroll-position/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import { type RefObject, useEffect, useState } from 'react';
import { useEventListener, _document } from '@raddix/use-event-listener';
import { useEventListener } from '@raddix/use-event-listener';

export interface ScrollPosition {
x: number | null;
y: number | null;
}

export interface Options<E extends HTMLElement> {
target?: RefObject<E> | Document | null;
target?: RefObject<E> | Document;
}

export const useScroll = <E extends HTMLElement = HTMLDivElement>({
target = _document
export const useScrollPosition = <E extends HTMLElement = HTMLDivElement>({
target = globalThis.document
}: Options<E> = {}): ScrollPosition => {
const [scrollPosition, setScrollPosition] = useState<ScrollPosition>({
x: 0,
y: 0
});

const handle = () => {
if (!target) return;
const targetElement =
target instanceof Document ? document.documentElement : target.current;

Expand All @@ -34,7 +33,7 @@ export const useScroll = <E extends HTMLElement = HTMLDivElement>({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEventListener(target, 'scroll', handle, { passive: true });
useEventListener('scroll', handle, { target, passive: true });

return scrollPosition;
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { renderHook, act } from '@testing-library/react';
import { useScroll } from '../src';
import { useScrollPosition } from '../src';

describe('useScroll test:', () => {
describe('useScrollPosition test:', () => {
let container: HTMLDivElement;

beforeEach(() => {
Expand All @@ -15,14 +15,14 @@ describe('useScroll test:', () => {
});

it('should initialize scroll position to (0, 0)', () => {
const { result } = renderHook(() => useScroll());
const { result } = renderHook(() => useScrollPosition());

expect(result.current).toEqual({ x: 0, y: 0 });
});

it('should update scroll position on scroll event', () => {
const { result } = renderHook(() =>
useScroll({ target: { current: container } })
useScrollPosition({ target: { current: container } })
);

expect(result.current).toEqual({ x: 0, y: 0 });
Expand All @@ -37,7 +37,7 @@ describe('useScroll test:', () => {
});

it('should update scroll position on document scroll event', () => {
const { result } = renderHook(() => useScroll());
const { result } = renderHook(() => useScrollPosition());

expect(result.current).toEqual({ x: 0, y: 0 });

Expand All @@ -50,23 +50,9 @@ describe('useScroll test:', () => {
expect(result.current).toEqual({ x: 50, y: 100 });
});

it('should not update scroll position if target is null', () => {
const { result } = renderHook(() => useScroll({ target: null }));

expect(result.current).toEqual({ x: 0, y: 0 });

act(() => {
document.documentElement.scrollTop = 100;
document.documentElement.scrollLeft = 50;
document.dispatchEvent(new Event('scroll'));
});

expect(result.current).toEqual({ x: 0, y: 0 });
});

it('should not update the scroll position if the element does not exist', () => {
const { result } = renderHook(() =>
useScroll({ target: { current: null } })
useScrollPosition({ target: { current: null } })
);

expect(result.current).toEqual({ x: null, y: null });
Expand Down
4 changes: 2 additions & 2 deletions packages/hooks/use-window-size/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { useEventListener, _window } from '@raddix/use-event-listener';
import { useEventListener } from '@raddix/use-event-listener';

interface Size {
width: number;
Expand All @@ -23,7 +23,7 @@ export const useWindowSize = (): Size => {
handleResize();
}, []);

useEventListener(_window, 'resize', handleResize);
useEventListener('resize', handleResize);

return windowSize;
};

0 comments on commit df1362f

Please sign in to comment.