/** * Minimal contract every `@42/core` controller satisfies so that any adapter * (React, Vue, Blade…) can wrap it with a single generic binding — no per * component glue beyond mapping options and events. * * A controller is constructed against existing DOM the consumer provides * (`new Controller(root, options?)`), exposes a way to subscribe to its DOM * `CustomEvent`s, and tears every side effect down on `destroy()`. * * `update()` and `getState()` are optional: adapters that need reactive option * syncing call `update()` when present and otherwise re-create the instance. */ export interface HeadlessController { /** Subscribe to a DOM event on the root element. Returns an unsubscribe fn. */ on(event: string, handler: (event: E) => void): () => void; /** Remove every listener / side effect. Must be idempotent. */ destroy(): void; /** Optional: sync reactive options without re-creating the instance. */ update?(options: Partial): void; /** Optional: read the current state (controlled-mode support). */ getState?(): State; } /** Constructor shape for a headless controller. */ export type HeadlessControllerClass = new ( root: HTMLElement, options?: Options, ) => HeadlessController;