import type { ShallowRef } from 'vue';
/**
 * Host-owned map of `field-uuid → the field's currently-resolved full option`.
 *
 * Selection-like fields (combobox, tree-select, …) persist only a *key* — the
 * scalar `optionValue` / `nodeKey` extracts from the chosen option. The rest of
 * the option object (a backend record's `code`, `label`, …) is in hand while the
 * field resolves the selection but is otherwise dropped. A *sibling* expression
 * — say a related select whose request needs the chosen option's `code` — has no
 * way to reach it: siblings share only the form state (the `form` CEL var), and
 * the persisted key deliberately doesn't carry the rest.
 *
 * This registry is that missing channel. The common host (the form root; a table
 * row) owns one and exposes it as the `selections` CEL variable; each select-like
 * field publishes its resolved option here under its own uuid. A sibling reads
 * `selections["<field-uuid>"].code`. It is NOT form state, so it never rides
 * along in the submit payload — that separation is the whole point.
 *
 * Keyed by field uuid, not by binding: a table cell's value lives in row data
 * (no form binding) while a form field's lives in form state, but the uuid is the
 * one identity both share — and the one the expression editor surfaces as a
 * field-name chip so the designer never sees the raw uuid.
 */
export type SelectionsRegistry = {
    /**
     * Live uuid → resolved-option map. Read by the host's `selections` thunk. A
     * `shallowRef`, deliberately: the stored options are opaque snapshots a
     * sibling expression reads but never the registry mutates, so deep-proxying
     * them is wasted work — and worse, it would replace the references we store
     * with reactive proxies, defeating the identity-based de-dup in `set`.
     * Reactivity rides on the `.value` swap alone (every `set`/`clear` replaces
     * the whole map), which is exactly what a `shallowRef` tracks.
     */
    entries: ShallowRef<Record<string, unknown>>;
    /** Publish (or replace) the resolved option for a field. */
    set: (uuid: string, option: unknown) => void;
    /** Drop a field's entry — on clear, or when the field unmounts. */
    clear: (uuid: string) => void;
};
/**
 * Create a registry and provide it to descendants. Called once per host (the
 * form root; later, a table row). The returned `entries` ref is what the host
 * overlays as the `selections` CEL thunk.
 */
export declare function provideSelectionsRegistry(): SelectionsRegistry;
/**
 * Inject the nearest registry, or `undefined` when there's no providing host
 * (an uncontrolled field, a unit test). Callers must tolerate the absent case —
 * publishing is best-effort.
 */
export declare function useSelectionsRegistry(): SelectionsRegistry | undefined;
/**
 * Wire a selection field's publish lifecycle to the nearest registry. Call once
 * in setup; it injects the host registry (tolerating absence), watches the
 * resolved selection, and clears on unmount.
 *
 * The de-dup is the whole point. A field's resolved-option computed re-mints on
 * every re-evaluation — and `cel.ts`'s `unwrapCelValue` deep-copies every CEL
 * result, so a remote option's backend record is a brand-new object on each
 * pass even when the underlying data is unchanged. Worse, `celBindings` reads
 * the `selections` map on every `$cel` call, so any publish re-triggers every
 * selectable's own option resolution. Publishing on each re-mint would replace
 * the map, re-trigger resolution, re-mint, and re-publish without bound — the
 * "Maximum recursive updates exceeded" loop. So we key on a STABLE selection
 * identity (the persisted key, or the ordered keys for multi), never the option
 * payload: the data is irrelevant to identity and is swept wholesale whenever
 * the selection actually changes. An unchanged selection is a no-op, which
 * keeps the `selections` reference stable and cuts the feedback at the source.
 *
 * `resolved` returns the value to publish, or `undefined` when nothing resolves
 * (cleared). `identity` projects that value to its stable selection key;
 * `raw` projects it to the payload stored for siblings to read.
 */
export declare function publishSelection<T>(key: string, resolved: () => T | undefined, project: {
    identity: (value: T) => string;
    raw: (value: T) => unknown;
}): void;
