Skip to content

Commit

Permalink
Merge pull request #7 from Hugos68/feat/event-listener
Browse files Browse the repository at this point in the history
Added useEventListener
  • Loading branch information
TGlide authored Apr 22, 2024
2 parents 9c5c777 + 283c388 commit b5c7fae
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-windows-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"runed": patch
---

New Function: `useEventListener`
1 change: 1 addition & 0 deletions packages/runed/src/lib/functions/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./useActiveElement/index.js";
export * from "./useDebounce/index.js";
export * from "./useElementSize/index.js";
export * from "./useEventListener/index.js";
1 change: 1 addition & 0 deletions packages/runed/src/lib/functions/useEventListener/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./useEventListener.svelte.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { ValueOrGetter } from "$lib/internal/types.js";
import { boxed } from "$lib/internal/utils/boxed.svelte.js";
import { addEventListener } from "$lib/internal/utils/event.js";

export function useEventListener<TEvent extends keyof WindowEventMap>(
target: ValueOrGetter<Window>,
event: TEvent,
handler: (this: Window, event: WindowEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): void;

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

export function useEventListener<
TElement extends HTMLElement,
TEvent extends keyof HTMLElementEventMap,
>(
target: ValueOrGetter<TElement>,
event: TEvent,
handler: (this: TElement, event: HTMLElementEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): void;

export function useEventListener(
target: ValueOrGetter<EventTarget>,
event: string,
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
): void;

export function useEventListener(
_target: ValueOrGetter<EventTarget>,
event: string,
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
) {
const target = boxed(_target);

$effect(() => addEventListener(target.value, event, handler, options));
}
58 changes: 58 additions & 0 deletions packages/runed/src/lib/internal/utils/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Overloaded function signatures for addEventListener
*/
export function addEventListener<TEvent extends keyof WindowEventMap>(
target: Window,
event: TEvent,
handler: (this: Window, event: WindowEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): VoidFunction;

export function addEventListener<TEvent extends keyof DocumentEventMap>(
target: Document,
event: TEvent,
handler: (this: Document, event: DocumentEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): VoidFunction;

export function addEventListener<
TElement extends HTMLElement,
TEvent extends keyof HTMLElementEventMap,
>(
target: TElement,
event: TEvent,
handler: (this: TElement, event: HTMLElementEventMap[TEvent]) => unknown,
options?: boolean | AddEventListenerOptions
): VoidFunction;

export function addEventListener(
target: EventTarget,
event: 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,
event: string | string[],
handler: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions
) {
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));

// Return a function that removes the event listener from the target element(s).
return () => {
events.forEach((_event) => target.removeEventListener(_event, handler, options));
};
}
29 changes: 29 additions & 0 deletions sites/docs/content/functions/use-event-listener.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: UseEventListener
description: A function that attaches an automatically disposed event listener.
---

<script>
import { UseEventListenerDemo } from '$lib/components/demos';
</script>

## Demo

<UseEventListenerDemo />

## Usage

```svelte
<script lang="ts">
import { useEventListener } from "runed";
let count = $state(0);
function increment() {
count++;
}
useEventListener(() => document, "click", increment);
</script>
<p>You've clicked {count} {count === 1 ? "Time" : "Times"}</p>
```
1 change: 1 addition & 0 deletions sites/docs/src/lib/components/demos/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as UseActiveElementDemo } from "./use-active-element.svelte";
export { default as UseDebounceDemo } from "./use-debounce.svelte";
export { default as UseElementSizeDemo } from "./use-element-size.svelte";
export { default as UseEventListenerDemo } from "./use-event-listener.svelte";
14 changes: 14 additions & 0 deletions sites/docs/src/lib/components/demos/use-event-listener.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script lang="ts">
import { useEventListener } from "runed";
let count = $state(0);
function increment() {
count++;
}
useEventListener(() => document, "click", increment);
</script>

<div class="select-none rounded-md bg-card p-8">
<p>You've clicked {count} {count === 1 ? "Time" : "Times"}</p>
</div>
5 changes: 5 additions & 0 deletions sites/docs/src/lib/config/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ export const navigation: Navigation = {
href: "/docs/functions/use-element-size",
items: [],
},
{
title: "useEventListener",
href: "/docs/functions/use-event-listener",
items: [],
},
],
},
],
Expand Down

0 comments on commit b5c7fae

Please sign in to comment.