Import
import { chainEvent } from "@typed/ui/Dom/index";This public exposure is a re-export. Its import path is supported; declaration documentation is shared with the other public exposures below.
Signatures
export declare function chainEvent<Ev extends Event, E1 = never, R1 = never, E2 = never, R2 = never>(user: EventHandlerInput<Ev, E1, R1>, internal: EventHandlerInput<Ev, E2, R2>): EventHandler.EventHandler<Ev, E1 | E2, R1 | R2> | undefined;Why
Component hosts must combine user and required behavior without hiding the precise Effect boundary. User callback invocation constructs the user Effect first. Internal callback invocation may then construct an internal Effect; only execution of that returned Effect is sequenced after the user Effect.
Ownership and lifetime
The returned EventHandler owns no listener by itself. The rendering Scope
installs it and removes it; once and AbortSignal state are honored for each
input independently. Capture and passive options are conservatively merged.
DOM behavior
The user handler receives a retained Proxy around the browser event so a
preventDefault() call made while its Effect runs can still cancel the
internal step. The proxy is not identity-equal to the native event. Its
properties—including currentTarget—are read from that native event, so
currentTarget becomes null after browser dispatch exactly as it normally
does. The internal handler receives the original native event, never the
proxy.
Invocation and Effect sequencing
userHandler.handler(proxy) is called first to construct userEffect. If
that invocation has already called preventDefault()—for example through an
EventHandler option—the internal handler is not invoked. Otherwise,
internalHandler.handler(nativeEvent) is called immediately to construct
internalEffect, before userEffect runs. A void-returning internal callback
therefore performs its callback body eagerly and cannot be undone by a later
preventDefault() inside userEffect. The composed Effect runs userEffect,
checks tracked default prevention again, and only then runs a returned
internalEffect when it is still allowed.
Examples
import { chainEvent } from "@typed/ui/Dom/Events"
import { EventHandler } from "@typed/template"
import { Effect } from "effect"
const calls: Array<string> = []
const handler = chainEvent(
EventHandler.make((event: MouseEvent) =>
Effect.sync(() => {
calls.push("user effect")
event.preventDefault()
})),
EventHandler.make(() => {
calls.push("internal callback") // runs while constructing the Effect
return Effect.sync(() => calls.push("internal effect"))
})
)!
const program = handler.handler(new MouseEvent("click", { cancelable: true }))
// calls is now ["internal callback"]
await Effect.runPromise(program)
// calls is ["internal callback", "user effect"];
// the returned internal Effect was gated by preventDefault.Other public imports
These import paths expose the same declaration. Each page retains its own public name and signature.