import type { EventManager } from './events';
import { type Getter } from './signal';
export interface Ref<T extends HTMLElement = HTMLElement> {
    current: T | null;
}
export declare const createRef: <T extends HTMLElement = HTMLElement>() => Ref<T>;
/** A single directly-appendable child: element, text, nested builder, or nothing.
 *  Internal helper — the public, general type is {@link Child}. */
type StaticChild = HTMLElement | string | ElementBuilder<any> | undefined | null;
/**
 * The one type every `children()` / `replaceChildren()` argument accepts —
 * fully composable (recursive): a node, text, nested builder, `null`/`undefined`,
 * a (nested) array, a {@link For}/{@link Index} handle for a keyed list, or a
 * getter `() => Child` marking a reactive region. A getter (or `Show`/`Switch`
 * branch) may itself return any `Child`, including a `For`/`Index` or another
 * getter — control-flow nests freely. On SSR getters / `For` / `Index` render once.
 */
export type Child = StaticChild | ForHandle | IndexHandle | Child[] | (() => Child);
declare const FOR_BRAND = "__ranFor";
/** Options for {@link For}. */
export interface ForOptions<T> {
    /** Reactive source array. Read inside an effect, so the list updates on change. */
    each: () => readonly T[] | null | undefined;
    /** Stable identity per item — **must be unique** within the list. Reused across
     *  updates to match old nodes to new items (that is what preserves DOM state). */
    key: (item: T, index: number) => string | number;
    /** Render one item to a single node. `index` is a **getter** (reactive): it
     *  reflects the item's current position even after the list reorders. Runs once
     *  per item (not on every list change) — drive per-item updates with signals. */
    render: (item: T, index: Getter<number>) => StaticChild;
}
/** Opaque handle returned by {@link For}; pass it straight to `children()`. */
export type ForHandle = {
    readonly [FOR_BRAND]: true;
};
/**
 * Keyed list for `children()`. Unlike a plain getter child (which rebuilds the
 * whole region on every change), `For` matches items by `key` and **reuses their
 * DOM nodes** — only added/removed/moved items touch the DOM, so focus, scroll,
 * input values and in-flight transitions inside surviving rows are preserved.
 *
 *   Ul().children(
 *     For({
 *       each: () => rows(),
 *       key: (r) => r.id,
 *       render: (r, i) => Li().text(() => `${i()}. ${r.title}`),
 *     }),
 *   );
 *
 * On SSR the list is rendered once as a static snapshot. Must be built inside a
 * `createRoot` so per-item scopes are disposed with the page.
 */
export declare function For<T>(options: ForOptions<T>): ForHandle;
/** Options for {@link Show}. */
export interface ShowOptions<T> {
    /** Condition source. Truthy → `children`, falsy → `fallback`. */
    when: () => T;
    /** Built when `when` is truthy. May return any {@link Child} — a `For`/`Index`
     *  list, a nested `Show`, etc. Receives an accessor to the narrowed value —
     *  read it inside a binding (`.text(() => v())`) to update without rebuilding. */
    children: (value: () => NonNullable<T>) => Child;
    /** Built when `when` is falsy. Omitted → nothing is rendered. */
    fallback?: () => Child;
}
/**
 * Fine-grained conditional child. Unlike a raw getter child (which re-runs on
 * **every** change it reads), `Show` rebuilds the branch **only when the
 * truthiness of `when` flips** — the condition is memoized. Content inside a
 * branch updates through its own bindings, not by re-running `Show`. This is the
 * SwiftUI/Solid model: build once, toggle only when the branch actually changes.
 *
 *   Show({
 *     when: () => user(),                       // reads a signal
 *     children: (u) => Div().text(() => u().name),
 *     fallback: () => Div().text('Signed out'),
 *   })
 *
 * `Show` returns a getter, so it is accepted anywhere `children()` takes a child.
 * Must be created inside a `createRoot` (it owns a memo + the branch effect).
 */
export declare function Show<T>(options: ShowOptions<T>): () => Child;
/** One branch of a {@link Switch}; build with {@link Match}. */
export interface MatchClause<T> {
    when: () => T;
    children: (value: () => NonNullable<T>) => Child;
}
/** Declare one `Switch` branch (identity helper — gives per-clause type inference). */
export declare function Match<T>(clause: MatchClause<T>): MatchClause<T>;
/** Options for {@link Switch}. */
export interface SwitchOptions {
    /** Branches, tried in order; the first with a truthy `when` renders. Clauses are
     *  heterogeneous (each `Match<T>` carries its own `T`), hence `any` here. */
    children: MatchClause<any>[];
    /** Rendered when no branch matches. Omitted → nothing. */
    fallback?: () => Child;
}
/**
 * Fine-grained multi-branch conditional (the n-way `Show`). Renders the first
 * `Match` whose `when` is truthy, else `fallback`. Only the **index of the
 * winning branch** is memoized, so it rebuilds only when the active branch
 * changes — not on every change a `when` reads. Evaluation short-circuits at the
 * first match (later branches aren't subscribed while an earlier one wins).
 *
 *   Switch({
 *     fallback: () => Span().text('idle'),
 *     children: [
 *       Match({ when: () => status() === 'loading', children: () => Spinner() }),
 *       Match({ when: () => error(), children: (e) => ErrorView(e) }),
 *     ],
 *   })
 */
export declare function Switch(options: SwitchOptions): () => Child;
declare const INDEX_BRAND = "__ranIndex";
/** Options for {@link Index}. */
export interface IndexOptions<T> {
    /** Reactive source array. */
    each: () => readonly T[] | null | undefined;
    /** Render the slot at a position. `item` is a **getter** (a signal): when the
     *  value at this index changes, it updates in place — the node is not rebuilt.
     *  `index` is a fixed number (the position never moves). */
    render: (item: () => T, index: number) => StaticChild;
}
/** Opaque handle returned by {@link Index}; pass it straight to `children()`. */
export type IndexHandle = {
    readonly [INDEX_BRAND]: true;
};
/**
 * Position-keyed list. The node at index `i` is **reused** across updates and its
 * `item` signal is updated in place — nodes never move. Use it when position is
 * the identity (primitive arrays, fixed-length rows). Use {@link For} instead
 * when items have a stable id and can reorder. SSR renders once.
 *
 *   Ul().children(
 *     Index({ each: () => nums(), render: (n, i) => Li().text(() => `${i}: ${n()}`) }),
 *   );
 */
export declare function Index<T>(options: IndexOptions<T>): IndexHandle;
export declare class ElementBuilder<T extends HTMLElement = HTMLElement> {
    private el;
    constructor(tag: string);
    id(value: string): this;
    /**
     * Apply a value now, or bind it reactively when a getter is passed.
     * A getter creates an effect owned by the current reactive scope (createRoot),
     * so the binding is disposed automatically when that scope is torn down.
     */
    private bind;
    class(name: string | Getter<string>): this;
    addClass(...names: string[]): this;
    removeClass(...names: string[]): this;
    attr(name: string, value: string | Getter<string>): this;
    attrs(values: Record<string, string | number | boolean | null | undefined>): this;
    boolAttr(name: string, value: boolean | Getter<boolean>, enabledValue?: string): this;
    part(value: string | Getter<string>): this;
    data(key: string, value: string | Getter<string>): this;
    style(keyOrMap: string | Record<string, string>, value?: string | Getter<string>): this;
    cssVar(name: string, value: string | Getter<string>): this;
    aria(key: string, value: string | Getter<string>): this;
    role(value: string | Getter<string>): this;
    tabIndex(value: number): this;
    label(value: string | Getter<string>): this;
    labelledBy(id: string | Getter<string>): this;
    describedBy(id: string | Getter<string>): this;
    ariaHidden(hidden?: boolean): this;
    /**
     * Permanent build-time listener — tied to the element's lifetime.
     * Use for internal shadow DOM elements created in the constructor.
     */
    on<K extends keyof HTMLElementEventMap>(type: K, listener: (this: T, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): this;
    /**
     * Lifecycle-managed listener — registered into an EventManager.
     * Use in connectedCallback when building elements that need cleanup on disconnect.
     * Call manager.abort() in disconnectedCallback to remove all listeners at once.
     */
    listen<K extends keyof HTMLElementEventMap>(manager: EventManager, type: K, handler: (this: T, ev: HTMLElementEventMap[K]) => any, options?: Omit<AddEventListenerOptions, 'signal'>): this;
    /**
     * Delegated listener — the built element acts as the parent container.
     * Fires handler only when the event originates from a descendant matching selector.
     * Registered into an EventManager so it is cleaned up with manager.abort().
     *
     *   Div().class('list')
     *     .children(...)
     *     .delegate(scope, '.item', 'click', (ev, item) => handleItem(item))
     *     .build();
     */
    delegate<K extends keyof HTMLElementEventMap>(manager: EventManager, selector: string, type: K, handler: (ev: HTMLElementEventMap[K], target: Element) => void, options?: Omit<AddEventListenerOptions, 'signal'>): this;
    children(...items: Child[]): this;
    replaceChildren(...items: Child[]): this;
    text(value: string | Getter<string>): this;
    ref(holder: Ref<T>): this;
    shadow(options?: ShadowRootInit): ShadowBuilder<T>;
    build(): T;
    serialize(): string;
}
export declare class ShadowBuilder<T extends HTMLElement = HTMLElement> {
    private root;
    private hostEl;
    private options;
    constructor(host: T, root: ShadowRoot, options: ShadowRootInit);
    children(...items: Child[]): this;
    adoptSheet(...sheets: CSSStyleSheet[]): this;
    css(cssText: string): this;
    done(): {
        host: T;
        shadow: ShadowRoot;
    };
    serialize(): string;
}
export {};
