Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup addEventListener #16

Merged
merged 5 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/olive-rivers-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"runed": patch
---

Fix addEventListener overloads
Original file line number Diff line number Diff line change
@@ -1,43 +1,65 @@
import { box } from "../box/box.svelte.js";
import type { MaybeBoxOrGetter } from "$lib/internal/types.js";
import { addEventListener } from "$lib/internal/utils/event.js";

/**
* Adds an event listener to the specified target element for the given event(s), and returns a function to remove it.
* @param target The target element to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
*/
export function useEventListener<TEvent extends keyof WindowEventMap>(
target: MaybeBoxOrGetter<Window | null | undefined>,
event: TEvent,
event: TEvent | TEvent[],
handler: (this: Window, event: WindowEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): void;

export function useEventListener<TEvent extends keyof DocumentEventMap>(
target: MaybeBoxOrGetter<Document | null | undefined>,
event: TEvent,
event: TEvent | TEvent[],
handler: (this: Document, event: DocumentEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): void;

/**
* Adds an event listener to the specified target element for the given event(s), and returns a function to remove it.
* @param target The target element to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
*/
export function useEventListener<
TElement extends HTMLElement,
TEvent extends keyof HTMLElementEventMap,
>(
target: MaybeBoxOrGetter<TElement | null | undefined>,
event: TEvent,
event: TEvent | TEvent[],
handler: (this: TElement, event: HTMLElementEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): void;

/**
* Adds an event listener to the specified target element for the given event(s), and returns a function to remove it.
* @param target The target element to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
*/
export function useEventListener(
target: MaybeBoxOrGetter<EventTarget | null | undefined>,
event: string,
event: string | string[],
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
): void;

export function useEventListener(
_target: MaybeBoxOrGetter<EventTarget | null | undefined>,
event: string,
event: string | string[],
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
) {
): void {
const target = box.from(_target);

$effect(() => {
Expand Down
61 changes: 42 additions & 19 deletions packages/runed/src/lib/internal/utils/event.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,81 @@
/**
* Overloaded function signatures for addEventListener
* Adds an event listener to the specified target element for the given event(s), and returns a function to remove it.
* @param target The target element to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
* @returns A function that removes the event listener(s) from the target element.
*/
export function addEventListener<TEvent extends keyof WindowEventMap>(
target: Window,
event: TEvent,
event: TEvent | TEvent[],
handler: (this: Window, event: WindowEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): VoidFunction;

/**
* Adds an event listener to the specified target element for the given event(s), and returns a function to remove it.
* @param target The target element to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
* @returns A function that removes the event listener(s) from the target element.
*/
export function addEventListener<TEvent extends keyof DocumentEventMap>(
target: Document,
event: TEvent,
event: TEvent | TEvent[],
handler: (this: Document, event: DocumentEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): VoidFunction;

/**
* Adds an event listener to the specified target element for the given event(s), and returns a function to remove it.
* @param target The target element to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
* @returns A function that removes the event listener(s) from the target element.
*/
export function addEventListener<
TElement extends HTMLElement,
TEvent extends keyof HTMLElementEventMap,
>(
target: TElement,
event: TEvent,
event: TEvent | TEvent[],
handler: (this: TElement, event: HTMLElementEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): VoidFunction;

/**
* Adds an event listener to the specified target element for the given event(s), and returns a function to remove it.
* @param target The target element to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
* @returns A function that removes the event listener(s) from the target element.
*/
export function addEventListener(
target: EventTarget,
event: string,
event: string | string[],
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
): VoidFunction;

/**
* Adds an event listener to the specified target element(s) for the given event(s), and returns a function to remove it.
* @param target The target element(s) to add the event listener to.
* @param event The event(s) to listen for.
* @param handler The function to be called when the event is triggered.
* @param options An optional object that specifies characteristics about the event listener.
* @returns A function that removes the event listener from the target element(s).
*/
export function addEventListener(
target: Window | Document | EventTarget,
target: EventTarget,
event: string | string[],
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
) {
): VoidFunction {
const events = Array.isArray(event) ? event : [event];

// Add the event listener to each specified event for the target element(s).
events.forEach((_event) => target.addEventListener(_event, handler, options));
for (const event of events) {
target.addEventListener(event, handler, options);
}

// Return a function that removes the event listener from the target element(s).
return () => {
events.forEach((_event) => target.removeEventListener(_event, handler, options));
for (const event of events) {
target.removeEventListener(event, handler, options);
}
};
}