-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from konstantin-lukas/useEvent
Use event
- Loading branch information
Showing
10 changed files
with
198 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React, {useEffect} from "react"; | ||
import { useEvent } from "../../src"; | ||
|
||
const DemoUseEvent = () => { | ||
const clickTarget = useEvent<HTMLDivElement>("click", (e) => { | ||
const t = (e.target as HTMLDivElement); | ||
t.style.backgroundColor = t.style.backgroundColor === "red" ? "green" : "red"; | ||
}); | ||
|
||
const windowTarget = useEvent("scroll", _ => console.log("scroll")); | ||
useEffect(() => { | ||
windowTarget(document); | ||
}, [windowTarget]); | ||
|
||
return ( | ||
<div | ||
ref={clickTarget} | ||
style={{ | ||
padding: 50, | ||
backgroundColor: "green", | ||
textAlign: "center", | ||
display: "inline-block", | ||
height: "150vh", | ||
}} | ||
> | ||
Click me :) | ||
</div> | ||
); | ||
}; | ||
|
||
export default DemoUseEvent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { useEffect, useState } from "react"; | ||
|
||
/** | ||
* Provides a wrapper around the EventListener API. Use the return value to define the event target. | ||
* @param type - {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#type See type on mdn web docs} | ||
* @param listener - {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#listener See listener on mdn web docs} | ||
* @param options - {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options See options on mdn web docs} | ||
* @param options.catpure - {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#capture See capture on mdn web docs} | ||
* @param options.once - {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#once See once on mdn web docs} | ||
* @param options.passive - {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#passive See passive on mdn web docs} | ||
* @param options.signal - {@link https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#signal See signal on mdn web docs} | ||
* @template T - The type of the event target. | ||
* | ||
* @return {@link https://react.dev/reference/react/useState SetStateAction} - A function which is used to assign the event target for convenience. The returned | ||
* value can be used like a ref when the target is an HTMLElement. If the target is the {@link window} or | ||
* {@link document}, you can use it like a regular {@link https://react.dev/reference/react/useState useState} setter. | ||
* | ||
* | ||
* @example | ||
* ```tsx | ||
* const DemoUseEvent = () => { | ||
* const clickTarget = useEvent<HTMLDivElement>("click", (e) => { | ||
* const t = (e.target as HTMLDivElement); | ||
* t.style.backgroundColor = t.style.backgroundColor === "red" ? "green" : "red"; | ||
* }); | ||
* | ||
* const windowTarget = useEvent("scroll", _ => console.log("scroll")); | ||
* useEffect(() => windowTarget(document), [windowTarget]); | ||
* | ||
* return ( | ||
* <div | ||
* ref={clickTarget} | ||
* style={{ height: "150vh" }} | ||
* > | ||
* Click me :) | ||
* </div> | ||
* ); | ||
* }; | ||
* ``` | ||
*/ | ||
function useEvent<T extends EventTarget>( | ||
type: string, | ||
listener: EventListener, | ||
options?: { | ||
capture?: boolean, | ||
once?: boolean, | ||
passive?: boolean, | ||
signal?: AbortSignal, | ||
}, | ||
) { | ||
const [target, setTarget] = useState<T | null>(null); | ||
useEffect(() => { | ||
if (target) { | ||
target.addEventListener(type, listener, options); | ||
return () => target.removeEventListener(type, listener, options); | ||
} | ||
}, [type, listener, target, options]); | ||
return setTarget; | ||
} | ||
|
||
export default useEvent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,33 @@ | ||
export { default as useFetch, FetchResult, FetchResultData, ParseType, FetchOptions } from "./hooks/useFetch"; | ||
export { default as useDefer } from "./hooks/useDefer"; | ||
export { default as useFirstRender } from "./hooks/useFirstRender"; | ||
export { default as useToggle } from "./hooks/useToggle"; | ||
export { default as useIntersectionObserver, IntersectionObserverOptions } from "./hooks/useIntersectionObserver"; | ||
export { default as useIntersectionObserverArray, IntersectionObserverArrayOptions } from "./hooks/useIntersectionObserverArray"; | ||
export { | ||
default as useFetch, | ||
type FetchResult, | ||
type FetchResultData, | ||
type ParseType, | ||
type FetchOptions, | ||
} from "./hooks/useFetch"; | ||
|
||
export { | ||
default as useDefer, | ||
} from "./hooks/useDefer"; | ||
|
||
export { | ||
default as useFirstRender, | ||
} from "./hooks/useFirstRender"; | ||
|
||
export { | ||
default as useToggle, | ||
} from "./hooks/useToggle"; | ||
|
||
export { | ||
default as useIntersectionObserver, | ||
type IntersectionObserverOptions, | ||
} from "./hooks/useIntersectionObserver"; | ||
|
||
export { | ||
default as useIntersectionObserverArray, | ||
type IntersectionObserverArrayOptions, | ||
} from "./hooks/useIntersectionObserverArray"; | ||
|
||
export { | ||
default as useEvent, | ||
} from "./hooks/useEvent"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { useEvent } from "../src"; | ||
import { fireEvent, render } from "@testing-library/react"; | ||
import { screen } from "@testing-library/dom"; | ||
import React, { useEffect } from "react"; | ||
|
||
function ElementEventComponent({ event }: { event: string }) { | ||
const target = useEvent<HTMLDivElement>(event, (e) => { | ||
const t = (e.target as HTMLDivElement); | ||
t.style.backgroundColor = t.style.backgroundColor === "green" ? "red" : "green"; | ||
}); | ||
return ( | ||
<div ref={target} data-testid="target-div"> | ||
Hello, world! | ||
</div> | ||
); | ||
} | ||
|
||
function WindowEventComponent({ event, spyFunction }: { event: string, spyFunction: () => void }) { | ||
const target = useEvent(event, spyFunction); | ||
useEffect(() => { | ||
target(window); | ||
}, [target]); | ||
return <></>; | ||
} | ||
|
||
test("should register events on elements and deregister them when props change", () => { | ||
|
||
const { rerender } = render(<ElementEventComponent event="mouseover"/>); | ||
const target = screen.getByTestId("target-div"); | ||
|
||
expect(target.style.backgroundColor).not.toBe("red"); | ||
expect(target.style.backgroundColor).not.toBe("green"); | ||
fireEvent.mouseOver(target, { target }); | ||
expect(target.style.backgroundColor).toBe("green"); | ||
|
||
rerender(<ElementEventComponent event="click"/>); | ||
fireEvent.mouseOver(target, { target }); | ||
expect(target.style.backgroundColor).toBe("green"); | ||
fireEvent.click(target, { target }); | ||
expect(target.style.backgroundColor).toBe("red"); | ||
|
||
}); | ||
|
||
test("should register events on the window and deregister them when props change", () => { | ||
|
||
const spyFunction = jest.fn(); | ||
const { rerender } = render(<WindowEventComponent event="mouseover" spyFunction={ spyFunction }/>); | ||
const target = window; | ||
|
||
expect(spyFunction).toHaveBeenCalledTimes(0); | ||
fireEvent.mouseOver(target, { target }); | ||
expect(spyFunction).toHaveBeenCalledTimes(1); | ||
|
||
rerender(<WindowEventComponent event="click" spyFunction={ spyFunction }/>); | ||
fireEvent.mouseOver(target, { target }); | ||
expect(spyFunction).toHaveBeenCalledTimes(1); | ||
fireEvent.click(target, { target }); | ||
expect(spyFunction).toHaveBeenCalledTimes(2); | ||
|
||
}); |