svelte-event
Version:
svelte-event provides a set of wrapper functions for adding modifiers to event handlers and a versatile `event` action for comprehensive event listener management in Svelte.
89 lines (75 loc) • 2.98 kB
text/typescript
// Modifier descriptions courtesy of Svelte docs: https://svelte.dev/docs/element-directives#on-eventname
import type { EventHandler, Modifiers } from '../types';
import { objectToEntries } from '../utils/objectToEntries.js';
import { pipe } from '../utils/pipe.js';
/** Calls `event.preventDefault()` before running the handler */
export function preventDefault<T extends Event, U extends HTMLElement>(handler: EventHandler<T>): EventHandler<T> {
return function (this: U, event: T) {
event.preventDefault();
handler.call(this, event);
};
}
/** Calls `event.stopPropagation()`, preventing the event reaching the next element */
export function stopPropagation<T extends Event, U extends HTMLElement>(handler: EventHandler<T>): EventHandler<T> {
return function (this: U, event: T): void {
event.stopPropagation();
handler.call(this, event);
};
}
/** Calls `event.stopImmediatePropagation()`, preventing other listeners of the same event from being fired. */
export function stopImmediatePropagation<T extends Event, U extends HTMLElement>(
handler: EventHandler<T>,
): EventHandler<T> {
return function (this: U, event: T): void {
event.stopImmediatePropagation();
handler.call(this, event);
};
}
/** Only triggers handler if the `event.target` is the element itself */
export function self<T extends Event, U extends HTMLElement>(handler: EventHandler<T>): EventHandler<T> {
return function (this: U, event: T): void {
if (event.target !== event.currentTarget) {
return;
}
handler.call(this, event);
};
}
/** Only trigger handler if event.isTrusted is true. I.e. if the event is triggered by a user action. */
export function trusted<T extends Event, U extends HTMLElement>(handler: EventHandler<T>): EventHandler<T> {
return function (this: U, event: T): void {
if (!event.isTrusted) {
return;
}
handler.call(this, event);
};
}
/** Remove the handler after the first time it runs */
export function once<T extends Event, U extends HTMLElement>(handler: EventHandler<T>): EventHandler<T> {
let hasBeenCalled = false;
return function (this: U, event: T): void {
if (hasBeenCalled) {
return;
}
handler.call(this, event);
hasBeenCalled = true;
};
}
export type WrappableModifiers = Omit<Modifiers, 'passive' | 'capture'>;
type WrappableModifierKey = keyof WrappableModifiers;
const modifierFunctionsByKey = {
preventDefault,
stopPropagation,
stopImmediatePropagation,
self,
trusted,
once,
} satisfies Record<string, (handler: EventHandler) => EventHandler>;
/** Wraps the handler with the modifiers specified in the second argument */
export function withModifiers<T extends Event>(
handler: EventHandler<T>,
modifiers: WrappableModifiers,
): (event: T) => void {
const enabledModifiers = objectToEntries(modifiers).filter(([key, value]) => value);
const modifierFunctions = enabledModifiers.map(([key]) => modifierFunctionsByKey[key]);
return pipe<EventHandler<T>>(handler, ...modifierFunctions);
}