import { LitElement } from "lit"; import type { PropertyValues, TemplateResult } from "lit"; export type FieldSize = "xs" | "sm" | "md" | "lg"; export interface FieldControlAria { id: string; /** undefined when there is no helper/error text — so a control's aria-describedby never points at an empty message node. */ describedBy: string | undefined; invalid: "true" | undefined; required: "true" | undefined; } /** * Abstract chrome + lifecycle base for every xmesh form field. * * Subclasses register with `@customElement("xm-")`; XmField itself is * never registered (it is not a usable element on its own). * * @fires input - Fired on each edit with the current value in `detail` (inherited by every field). * @fires change - Fired on commit with the new value in `detail` (inherited by every field). */ export declare abstract class XmField extends LitElement { static styles: CSSStyleSheet[]; static formAssociated: boolean; static shadowRootOptions: ShadowRootInit; label: string; helper: string; /** Severity copy. Non-empty ⇒ the field is in error (icon + copy, never color). */ error: string; size: FieldSize; required: boolean; disabled: boolean; readonly: boolean; loading: boolean; /** Form-control name — mirrors native . */ name: string; /** INITIAL value (uncontrolled-first, AD-6): the `value` attribute seeds the live state once, then never overrides user input. Mapped from attribute `value` so authors write ``. */ initialValue: string; /** INITIAL checked for toggle subclasses; mapped from attribute `checked`. */ initialChecked: boolean; /** Live value state — seeded from `initialValue`, then owned by the field. */ protected _value: string; /** Live checked state (toggle subclasses) — seeded from `initialChecked`. */ protected _checked: boolean; /** True once a toggle subclass has declared itself, so the form value is submitted as checked-state rather than text. Set eagerly by overriding `isToggle`, or lazily on the first `emitToggle`. */ protected _toggle: boolean; /** OR-propagated disabled flag a future xm-form sets — never re-enables a self-disabled field (AD-6a / AD-9a). */ private _formDisabled; protected readonly internals: ElementInternals; private readonly _seq; private readonly _controlId; private readonly _describedById; private _valueSeeded; protected _dirty: boolean; constructor(); connectedCallback(): void; protected willUpdate(changed: PropertyValues): void; /** Whether this field submits checked-state (toggle) rather than text. Toggle subclasses (checkbox / radio / switch) override this to return `true` so their form value is correct from first paint — before any interaction — and is never inferred from `initialChecked` (a declaratively-checked text field must NOT be treated as a toggle, and an untouched unchecked toggle must submit `null`, not `""`). */ protected get isToggle(): boolean; /** Effective disabled = own disabled OR a future xm-form down-propagation. OR semantics: neither source can re-enable what the other disabled. */ protected get effectiveDisabled(): boolean; /** Non-interactive whenever disabled (either source), readonly, or loading. */ protected get nonInteractive(): boolean; protected get isError(): boolean; /** True when the message row has helper or error copy to describe. */ protected get hasMessage(): boolean; /** Public read contract for xm-form (AD-6a/AD-12): live value, no shadow reach. */ get value(): string; /** Programmatic reset support — setting `value` after first paint updates live state. */ set value(next: string); /** Public read contract for toggle subclasses (AD-6a). */ get checked(): boolean; set checked(next: boolean); /** Down-propagation hook: xm-form (Story 2.10) sets this; it OR's with the field's own disabled and can never re-enable a self-disabled field. */ setFormDisabled(disabled: boolean): void; /** Per-keystroke / per-drag live update. Updates live state, syncs the form value, and emits a composed, bubbling `input` with a typed primitive detail. */ protected emitInput(value: string): void; /** Commit. Same payload shape as input; fire on blur / Enter / native change. */ protected emitChange(value: string): void; /** Toggle commit — marks the field a toggle and emits `detail.checked` (AD-8a). */ protected emitToggle(checked: boolean): void; private _syncFormValue; /** * The ARIA hooks the chrome wires. Subclasses set `id`, `aria-describedby`, * `aria-invalid`, and `aria-required` on their control element from these so * the rendered label associates with the control and the error string is * announced (NFR-13 / UX-DR7). */ protected get controlAria(): FieldControlAria; /** * Subclasses override to render their concrete control directly into shadow * DOM. The default projects whatever the author slots as `slot="control"`, * so a subclass can also author the control as a light-DOM child. Either * path keeps the chrome on the base (AD-7). */ protected renderControl(): TemplateResult; render(): TemplateResult; }