/** * Low-level Effect wrappers for EventTarget APIs. * @since 8.19.0 */ import * as Effect from "effect/Effect" import { dual } from "effect/Function" import * as Scope from "effect/Scope" import { GlobalThis } from "./GlobalThis.js" import { createScopedRuntime, type DefaultEventMap } from "./internal/_helpers.js" /** * Add an event listener to an EventTarget * @since 8.19.0 * @category events */ export interface AddEventListenerOptions extends globalThis.AddEventListenerOptions { readonly eventName: EventName readonly handler: ( event: EventWithCurrentTarget ? DefaultEventMap[EventName] : Event> ) => Effect.Effect } /** * Add an event listener to an EventTarget * @since 8.19.0 * @category events */ export const addEventListener: { ( options: AddEventListenerOptions ): (target: T) => Effect.Effect ( target: T, options: AddEventListenerOptions ): Effect.Effect } = dual( 2, function addEventListener( target: T, options: AddEventListenerOptions ) { return Effect.gen(function*() { const { run, scope } = yield* createScopedRuntime() const listener = (event: Event) => run(options.handler(event as any)) const removeListener = addEventListener_(target, options.eventName, listener, options) yield* Scope.addFinalizer(scope, Effect.sync(removeListener)) }) } ) function addEventListener_( target: EventTarget, event: string, listener: EventListenerOrEventListenerObject, options?: globalThis.AddEventListenerOptions ): () => void { target.addEventListener(event, listener, options) return () => { target.removeEventListener(event, listener, options) } } /** * Dispatch an event from an EventTarget * @since 8.19.0 * @category events */ export const dispatchEvent: { >( event: EventName, options?: EventInit ): (target: T) => Effect.Effect >( target: T, event: EventName, options?: EventInit ): Effect.Effect } = dual(3, function dispatchEventWith< T extends EventTarget, EventName extends keyof DefaultEventMap >(target: T, event: EventName, options?: EventInit): Effect.Effect { return GlobalThis.with((globalThis) => target.dispatchEvent(new globalThis.Event(event as string, options))) }) /** * Check to see if a key modifier is being used * @since 8.19.0 * @category events */ export function isUsingKeyModifier(event: KeyboardEvent | MouseEvent): boolean { return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey } /** * Helper for creating an Event that has the target property set. * @since 8.19.0 * @category events */ export type EventWithTarget = Ev & { target: T } /** * Helper for creating an Event that has the currentTarget property set. * @since 8.19.0 * @category events */ export type EventWithCurrentTarget = Ev & { currentTarget: T }