import { nothing, PropertyValues, TemplateResult } from 'lit'; import { FieldDescriptor } from '../core/types.js'; import { BahtElement } from './base.js'; /** * Shared shape of every field primitive: descriptor + value in, `baht-input` out. * Dumb and controlled — never mutates its own `value` prop; the host re-feeds it. * * `controlId` carries the base class `uid`: the same field key renders once per repeater * row (and can repeat across forms on one page), so key-only ids collide — worst for * radios, whose shared native `name` merges groups. */ export declare abstract class BahtFieldBase extends BahtElement { /** * Default trailing debounce (ms) for TYPED edits — text, email, password, * textarea, number. Every keystroke otherwise re-runs the host's rules, * validation and dependent-option fetches. Per element: the `debounce` * property/attribute; `` sets it for a whole * form. 0 = emit on every keystroke. Selects, checkboxes, radios, toggles, * dates and files are never debounced — a pick is one event. */ static defaultDebounce: number; field: FieldDescriptor; value: unknown; disabled: boolean; readonly: boolean; required: boolean; /** Append the localized "(optional)" marker to the label when not required (set by ). */ showOptional: boolean; error: string | null; /** Debounce for typed edits (ms); unset = BahtFieldBase.defaultDebounce. */ debounce?: number; /** * The keystrokes not yet (or just) handed to the host. The control keeps * rendering `typed.value` until the host's `value` moves, so a re-render * mid-typing (a sibling field changing) can't snap the text back. */ private typed; private typedTimer; private readonly onFocusOut; connectedCallback(): void; disconnectedCallback(): void; protected willUpdate(changed: PropertyValues): void; protected get effectiveDebounce(): number; /** A typed edit: emitted after `debounce` ms of quiet (or at once when 0). */ protected emitTyped(value: unknown): void; /** Hand a pending typed edit to the host now (blur, disconnect, host reads). Idempotent. */ flushTyped(): void; /** What a typed control shows: pending keystrokes win over a stale host value. */ protected get shownValue(): unknown; /** `shownValue` as control text: `''` for null/undefined, `String()` otherwise. */ protected get shownText(): string; /** * `field` as the host may actually have left it: a framework can connect the element * before it binds the descriptor, so internally it is optional until then. */ protected get assignedField(): FieldDescriptor | undefined; /** Emit the user's edit upward (composed so it crosses any boundary). */ protected emitInput(value: unknown): void; protected abstract renderControl(): TemplateResult; /** True when `field.icon` names a real icon — gates both the icon markup * and the control's icon-padding class, so a typo/removed name never * leaves the control indented for a glyph that isn't there. */ protected get hasFieldIcon(): boolean; /** Leading icon for text/currency/textarea/dropdown controls (spec: field.icon). */ protected renderFieldIcon(): TemplateResult | typeof nothing; protected renderLabel(): TemplateResult | typeof nothing; /** Required asterisk, or the "(optional)" marker when the form asks for it. */ protected renderLabelMark(): TemplateResult | typeof nothing; protected get controlId(): string; protected get labelId(): string; protected get errorId(): string; protected get helpId(): string; /** id list for the control's aria-describedby: error first, then help. */ protected get describedBy(): string | typeof nothing; /** 'true' while the field is in error, else absent (styles hook on [aria-invalid]). */ protected get invalidAttr(): string | typeof nothing; protected render(): TemplateResult | typeof nothing; }