import * as _angular_core from '@angular/core'; import { WritableSignal, Signal, Injector, InjectionToken, Provider, TemplateRef, OnInit, ElementRef, InputSignal, OnDestroy, InputSignalWithTransform } from '@angular/core'; import * as _modyra_core from '@modyra/core'; import { MdyFormAdapter as MdyFormAdapter$1, MdyWritableSignal, MdySignal, MdyFormState as MdyFormState$1, MdyFieldState as MdyFieldState$1, MdyFormError, MdyControlOption, ValidatorFn, MdySelectOption, MdyFormRegistry, MdyFormEngine, MdySubmitMode, MdySecurityPolicy, MdyAnyArrayDescriptor as MdyAnyArrayDescriptor$1, MdyAnyFieldDescriptor as MdyAnyFieldDescriptor$1, MdyAnyGroupDescriptor as MdyAnyGroupDescriptor$1, MdyAnyRecordDescriptor as MdyAnyRecordDescriptor$1, MdyAnyRowDescriptor as MdyAnyRowDescriptor$1, MdyArrayDescriptor as MdyArrayDescriptor$1, MdyArrayHandle as MdyArrayHandle$1, MdyArrayItemValue as MdyArrayItemValue$1, MdyFieldHandle as MdyFieldHandle$1, MdyFieldDescriptor as MdyFieldDescriptor$1, MdyFormSchema as MdyFormSchema$1, MdyGroupDescriptor as MdyGroupDescriptor$1, MdyRecordDescriptor as MdyRecordDescriptor$1, MdyRecordHandle as MdyRecordHandle$1, MdyFieldOptions as MdyFieldOptions$1, MdyTypedFormBaseOptions, MdyFormPatch as MdyFormPatch$1, MdyFormValue as MdyFormValue$1, MdyFormSubmitEvent, MdyTypedFormBase, MdySubmittedValue, MdyWiden as MdyWiden$1, MdyGroupOptions, MdyFormValidatorFn, MdyAsyncValidatorFn, MdyAsyncValidatorOptions, MdySanitizer, MdyDynamicField, MdyTimepickerViewMode, MdyTimeGranularity, MdyDynamicParseMode, MdyDynamicDiagnostic, MdyDynamicLayoutNode, MdyDynamicLayoutChild, MdyFieldError, MdyFieldConstraints, MdyDateRange, MdyMultiselectMode, MdyDiagnostics, MdyReactivity } from '@modyra/core'; export { MdyAsyncValidatorFn, MdyAsyncValidatorOptions, MdyControlOption, MdyDateRange, MdyDraftOptions, MdyDraftStorage, MdyFieldError, MdyFormError, MdyFormSubmitEvent, MdyFormValidatorFn, MdySanitizeProfile, MdySanitizer, MdySecurityPolicy, MdySecurityViolation, MdySecurityViolationKind, MdySelectOption, MdySubmitMode, ValidatorFn } from '@modyra/core'; import * as _modyra_angular from '@modyra/angular'; import * as _modyra_widgets from '@modyra/widgets'; import { MdyI18nMessages, MdyBuiltInLocale, MdyPartContract, MdyWidgetKind, MdyValueWidgetIntent, MdyOverlayCoords, MdyOverlayBranch, MdyDatepickerFieldController, MdyDaterangeFieldController, scrollChipStripByWheel, MdyTimepickerViewMode as MdyTimepickerViewMode$1, MdyTimepickerFieldIntent, MdyWidgetCommandHandlers, MdyUiCommand, MdySelectState, MdySelectFieldController, MdySelectFieldControllerOptions, MdySelectIntent } from '@modyra/widgets'; import { MdyDateLocale, MdyTimeFormat, CalendarCell, CalendarDate } from '@modyra/core/datetime'; import { SafeHtml } from '@angular/platform-browser'; /** * Re-brands the engine's structural signals as Angular's own. * * The engine describes reactivity through a minimal contract whose signal type is a bare `(): T`. * At runtime these controls are built on Angular's primitives, so the branded types are accurate — * and derived rather than restated, so a member added to the engine's state arrives here with no * edit and the two cannot describe different shapes. * * Only sound for a type whose members are all signals: a zero-argument method is structurally a * signal too and would be re-branded into one. */ type AsAngularSignals = { readonly [K in keyof T]: T[K] extends MdyWritableSignal ? WritableSignal : T[K] extends MdySignal ? Signal : T[K]; }; /** Reactive state of a single field, with Angular-branded signals. */ type MdyFieldState = AsAngularSignals>; /** Callable that returns the FieldState for a field. */ type MdyFieldRef = () => MdyFieldState; /** * Maps a form model type `T` to a tree of field refs, mirroring the model shape. * Each key of `T` becomes an `MdyFieldRef` for its corresponding value type. */ type MdyFieldTree> = { readonly [K in keyof T]: MdyFieldRef; }; /** * Interface for components that support options override (e.g. Select, Multiselect). * Used by conditional directives to avoid circular dependencies. */ interface MdyOptionsControl { readonly overrideOptions: WritableSignal[] | null>; readonly options: Signal[]>; readonly loading: Signal; readonly loadingOverride: WritableSignal; /** Current search query typed in the control's search input. */ readonly searchQuery: Signal; resetSelection(): void; } interface MdyControlRendererConfig { readonly label?: string; readonly hint?: string; readonly placeholder?: string; readonly options?: ReadonlyArray>; } /** Reactive state of the whole form, with Angular-branded signals. */ type MdyFormState = AsAngularSignals; /** * The engine's adapter contract with Angular-branded reactive members. * * Extends the engine's rather than repeating it, so every method — and every method the engine * gains — is inherited. {@link AsAngularSignals} cannot be applied wholesale here: `getValue(): T` * is structurally a signal and would be re-branded into one, so the two genuinely reactive members * are overridden by name and nothing else is touched. * * Reset semantics, which the engine's own documentation does not fix: * - Fields with an explicit `[initialValue]` binding reset to that value. * - Fields seeded only via `[formValue]` reset to `null`; `[formValue]` is a prefill seed, not a * persistent reset target. * - All `touched` and `dirty` states are cleared. */ interface MdyFormAdapter> extends Omit, "state" | "value" | "getField"> { readonly state: MdyFormState; /** Reactive signal that emits the current form value on every change. */ readonly value: Signal; getField(name: K): MdyFieldRef | null; errorsFor(path: keyof T | string): Signal>; } interface MdyFormContext { readonly valid: Signal; readonly submitting: Signal; readonly submitCount: Signal; readonly lastSubmitErrors: Signal>; } interface MdyFieldConfig { readonly name: string; readonly validators?: ReadonlyArray>; readonly initialValue?: TValue; readonly disabled?: boolean; } /** * The flat path protocol controls and validator directives speak. * Angular specialization of the framework-agnostic core registry contract. */ type MdyDeclarativeRegistry = MdyFormRegistry>; /** * Adapter used when `` runs without an explicit [adapter] input, * and the engine underneath `mdyForm()`. * * Since the domain-model extraction this class is a thin Angular binding of * the framework-agnostic {@link MdyFormEngine} from `@modyra/core`: it feeds * the engine Angular's native signal primitives (via `angularReactivity`), * so every piece of form state is a real Angular signal that participates * in change detection — zoneless included. All semantics (lazy fields, * keyed validators, async last-wins, drafts, history, server-error * snapshots) live in the engine. */ declare class MdyDeclarativeAdapter extends MdyFormEngine implements MdyFormAdapter>, MdyDeclarativeRegistry { constructor(formValue: Signal | undefined>, submitMode?: Signal, /** Needed to run async validators, drafts and history. */ injector?: Injector, /** Injection-prevention policy for field values (see `@modyra/core` security). */ security?: MdySecurityPolicy); readonly state: MdyFormState; readonly value: Signal>; readonly fieldNames: Signal; readonly hasDraft: Signal; readonly canUndo: Signal; readonly canRedo: Signal; getField(name: string): MdyFieldRef | null; errorsFor(path: string): Signal>; } /** * Scoped to MdyFormComponent via providers[]. * Injected by renderer components to resolve FieldRefs. */ declare const MDY_FORM_ADAPTER: InjectionToken, Partial>>>; /** * When provided on an element injector, renderers display errors * inline next to the label rather than as a block below the input. */ declare const MDY_INLINE_ERRORS: InjectionToken; /** * Provided by MdyFloatingLabelsDirective to enable floating labels globally on a form. */ declare const MDY_FLOATING_LABELS: InjectionToken<_modyra_angular.MdyFloatingLabelsDirective>; /** * Global default for whether floating labels are enabled. * Override at application root to change the default for all forms. * Defaults to `false` (floating labels opt-in via `mdyFloatingLabels` directive). */ declare const MDY_FLOATING_LABELS_DEFAULT: InjectionToken; /** * Global default density for floating labels. * Replicates M3 density semantics: 0 = standard 56px, negative values compact. * Defaults to `-2` (48px, balanced compactness). */ declare const MDY_FLOATING_LABELS_DENSITY_DEFAULT: InjectionToken; /** * Provided by MdyFormComponent in declarative mode (no explicit [adapter] input). * Validator directives inject this to register their rules on specific fields. */ declare const MDY_DECLARATIVE_REGISTRY: InjectionToken; /** * All static UI strings used by modyra renderers. * Override by providing `MDY_I18N_MESSAGES` at the root or component level. * * @example * providers: [{ provide: MDY_I18N_MESSAGES, useValue: { ...MDY_I18N_MESSAGES_DEFAULT, noResults: 'Nessun risultato' } }] */ declare const MDY_I18N_MESSAGES: InjectionToken; interface MdyLocaleOptions { /** * BCP 47 tag for `Intl`-based date formatting (month/day names, first day * of week). Defaults to the canonical tag of the language preset. */ readonly dateLocale?: string; /** Per-key overrides applied on top of the language preset. */ readonly overrides?: Partial; } /** * Provides both UI strings and date localisation with one call: * * ```ts * bootstrapApplication(App, { * providers: [provideModyraLocale("it")], * }); * ``` * * Built-in presets: `en`, `it`, `de`, `fr`, `es`. Use `overrides` to adjust * individual keys, or provide `MDY_I18N_MESSAGES` yourself for other * languages (the token is a plain object of strings). */ declare function provideModyraLocale(locale: MdyBuiltInLocale, options?: MdyLocaleOptions): Provider[]; /** * DI token that provides locale configuration for date components. * * The locale shape and builder are framework-agnostic and come from * `@modyra/core`; Angular keeps only the token/provider wiring here. */ declare const MDY_DATE_LOCALE: InjectionToken; type MdyAnyArrayDescriptor = MdyAnyArrayDescriptor$1; type MdyAnyFieldDescriptor = MdyAnyFieldDescriptor$1; type MdyAnyGroupDescriptor = MdyAnyGroupDescriptor$1; type MdyAnyRecordDescriptor = MdyAnyRecordDescriptor$1; type MdyAnyRowDescriptor = MdyAnyRowDescriptor$1; type MdyArrayDescriptor = MdyArrayDescriptor$1; type MdyRecordDescriptor = MdyRecordDescriptor$1; type MdyArrayItemValue = MdyArrayItemValue$1; type MdyFieldDescriptor = MdyFieldDescriptor$1; type MdyFieldOptions = MdyFieldOptions$1; type MdyFormPatch = MdyFormPatch$1; type MdyFormSchema = MdyFormSchema$1; type MdyFormValue = MdyFormValue$1; type MdyGroupDescriptor = MdyGroupDescriptor$1; type MdyWiden = MdyWiden$1; /** * Typed handle for a single field, exposed on `form.f`. * Bind it to a renderer with `[field]="form.f.email"` — a typo on the * handle path is a compile error, unlike the stringly `name` attribute. */ /** * Typed handle for a single field, with Angular-branded signals. * * Derived from the engine's handle rather than restated. Written out member by member it drifted the * moment the engine gained one: `interactivity` and `readonly` arrived in the contract and not in * the copy, so a handle built here satisfied this file's idea of the type, compiled, and threw * `handle.readonly is not a function` the first time a widget controller asked. */ type MdyFieldHandle = AsAngularSignals, MdyFieldHandleCommands>> & Pick, MdyFieldHandleCommands>; /** The handle's imperative half: what a renderer calls, as against what it reads. */ type MdyFieldHandleCommands = "set" | "markAsTouched" | "markAsDirty"; /** * Typed handle for a repeatable array item, exposed on `form.f` (`form.f.items`). * * Derived from the engine's handle, like the field handle above and for the same reason: written out * member by member it satisfies this file's idea of the type and drifts the moment the engine gains * one. */ type MdyArrayHandle = AsAngularSignals, MdyArrayHandleCommands>> & Pick, MdyArrayHandleCommands>; /** The array handle's imperative half: what a renderer calls, as against what it reads. */ type MdyArrayHandleCommands = "push" | "insert" | "remove" | "move" | "setAll" | "at"; /** * Typed handle for a collection keyed by data, exposed on `form.f` (`form.f.rows`). * * The core's shape with this framework's signal type — the members are the core's, and their meaning * is documented there. */ type MdyRecordHandle = AsAngularSignals, MdyRecordHandleCommands>> & Omit, MdyRecordHandleCommands>, "cell"> & { cell(key: string, path?: string): MdyFieldHandle; }; /** The record handle's imperative half. */ type MdyRecordHandleCommands = "has" | "row" | "cell" | "upsert" | "remove" | "setAll" | "patch" | "rename" | "validOf"; /** * The handle tree for a single row — a field handle, a nested group tree, or the collection a row * of a record may itself hold. The two collection arms return this framework's own handle types, * so a nested handle carries Angular's signals exactly like a top-level one. */ type MdyItemHandleTree = I extends MdyGroupDescriptor ? MdyFieldHandleTree : I extends MdyFieldDescriptor ? MdyFieldHandle : I extends MdyRecordDescriptor ? MdyRecordHandle, MdyArrayItemValue> : I extends MdyArrayDescriptor ? MdyArrayHandle, MdyArrayItemValue> : never; /** The typed handle tree mirroring the schema shape (`form.f.address.city`). */ type MdyFieldHandleTree = { readonly [K in keyof S]: S[K] extends MdyFieldDescriptor ? MdyFieldHandle : S[K] extends MdyGroupDescriptor ? MdyFieldHandleTree : S[K] extends MdyArrayDescriptor ? MdyArrayHandle, MdyArrayItemValue> : S[K] extends MdyRecordDescriptor ? MdyRecordHandle, MdyArrayItemValue> : never; }; /** Declares a typed leaf field of a {@link mdyForm} schema. */ declare function field(initial: MdyWiden, validators?: ReadonlyArray>>, options?: MdyFieldOptions>): MdyFieldDescriptor>; /** * Declares a nested group of fields (`address.city` paths on the adapter). * * `options.when` says the whole section is only in play under a condition — see * {@link MdyGroupOptions}. A wrapper that dropped it would make the Angular schema quietly poorer * than the one every other adapter writes. */ declare function group(children: TChildren, options?: MdyGroupOptions): MdyGroupDescriptor; /** Declares a repeatable array of fields or groups (`items.0.name` paths on the adapter). */ declare function array(item: TItem, options?: { readonly initial?: ReadonlyArray; readonly validators?: ReadonlyArray>; }): MdyArrayDescriptor; /** Declares a collection keyed by data (`rows.a3f9.name` paths on the adapter). */ declare function record(item: TItem, options?: { readonly initial?: Readonly>; readonly validators?: ReadonlyArray>>>; }): MdyRecordDescriptor; interface MdyFormOptions = Record> extends MdyTypedFormBaseOptions { readonly submitMode?: MdySubmitMode; /** * Needed only for async validators when `mdyForm()` is called outside an * injection context; inside a field initializer it is resolved automatically. */ readonly injector?: Injector; } /** * Structural supertype of every `MdyTypedForm` — what `` * accepts without caring about the concrete schema type. Mirrors * `MdyFormAdapter` with schema-agnostic value types. */ interface MdyTypedFormLike extends MdyDeclarativeRegistry { readonly state: MdyFormState; readonly value: Signal>; getValue(): Record; /** Every field except the disabled ones — what a submit actually sends. */ submitValue(): Partial>; getField(name: string): MdyFieldRef | null; errorsFor(path: string): Signal>; submit(action: (value: Partial>) => Promise | MdyFormError[] | void): Promise; markAllTouched(): void; buildSubmitEvent(value: never): MdyFormSubmitEvent, Partial>>; patchValue(partial: never): void; setValue(value: never): void; reset(): void; } /** * Creates a typed, signal-based form model from a schema. * * ```ts * const form = mdyForm({ * email: field("", [required(), email()]), * age: field(null, [min(18)]), * address: group({ city: field(""), zip: field("") }), * }); * * form.f.email.value(); // Signal * form.f.address.city.set("Rome"); * form.getValue().age; // number | null — typos do not compile * ``` * ```html * * * * ``` */ declare function mdyForm(schema: S, options?: MdyFormOptions>): MdyTypedForm; /** * Typed form model over the flat {@link MdyDeclarativeAdapter}. * * Inherits all framework-agnostic behavior from {@link MdyTypedFormBase} in * `@modyra/core`; this class only adds Angular signal narrowing and the * injector-aware constructor. */ declare class MdyTypedForm extends MdyTypedFormBase, Signal> implements MdyFormAdapter, MdySubmittedValue>, MdyDeclarativeRegistry { protected readonly _adapter: MdyDeclarativeAdapter; readonly state: MdyFormState; readonly f: MdyFieldHandleTree; readonly value: Signal>; constructor(schema: S, options?: MdyFormOptions>); getField>(name: K): MdyFieldRef[K]> | null; getField(name: string): MdyFieldRef | null; errorsFor(path: keyof MdyFormValue | string): Signal>; get canUndo(): Signal; get canRedo(): Signal; get hasDraft(): Signal; get fieldNames(): Signal; protected _buildHandle(path: string): MdyFieldHandle; } /** * Pure state-manager for a dynamically-sized list of repeating sub-forms. * * Manages the items array (add/remove) and collects values/validity from * `` content children. The consumer renders the forms directly * in its own template so Angular DI works correctly for renderer components. * * Usage: * ```html * * @for (item of arr.items(); track item._id; let idx = $index) { * * * * * } * * * ``` * * Read results with `arr.getValue()` and validity with `arr.isValid()`. */ declare class MdyFormArrayComponent> { /** Seed values for the initial rows. Re-setting this input resets all rows. */ readonly initialItems: _angular_core.InputSignal; private _nextId; /** * Reactive items list — bind this in the consumer's `@for` to drive the rows. * Each entry carries a stable `_id` for `track` and the row seed `value`. * Seeds are `Partial`: rows added without a value start empty and get * completed by the user (B43 — no unsound `Partial as T` cast). */ readonly items: WritableSignal; }>>; /** All `` content children, in DOM order. */ private readonly _forms; /** Aggregated validity signal — `true` when every row form is valid. */ readonly state: Signal<{ valid: boolean; }>; /** Returns `true` when every row form is valid. */ isValid(): boolean; /** * Collects and returns the current value of every row form, in DOM order. * Rows are typed `Partial`: a row whose controls have not all been * filled does not contain those keys. Validate with `isValid()` before * treating entries as complete `T` (B43). */ getValue(): Array>; /** Appends a new row pre-filled with the given partial value. */ add(value?: Partial): void; /** Removes the row at the given index. */ remove(index: number): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; static ɵcmp: _angular_core.ɵɵComponentDeclaration, "mdy-form-array", never, { "initialItems": { "alias": "initialItems"; "required": false; "isSignal": true; }; }, {}, ["_forms"], ["*"], true, never>; } /** * Host component for a declarative signal-driven form. * * Provides the adapter to all descendant renderer components via DI. * * **Explicit adapter mode** (existing API, unchanged): * ```html * * ``` * * **Declarative mode** (no adapter needed): * ```html * * * * * ``` */ declare class MdyFormComponent, TSubmit = Partial> implements MdyFormAdapter, MdyDeclarativeRegistry { /** Explicit adapter — if omitted the form creates one automatically. */ readonly adapter: _angular_core.InputSignal | undefined>; /** * Typed form model created with `mdyForm()`. Takes precedence over the * internal declarative adapter; `[adapter]` still wins over both. * `[formValue]` is ignored in this mode — initial values live in the schema. */ readonly form: _angular_core.InputSignal<(MdyFormAdapter & MdyDeclarativeRegistry) | undefined>; /** * The submit action. * * Receives `Partial`, not `T`: a disabled field is not submitted, and any field may be * disabled at runtime. Read a key defensively rather than assuming the form's shape. */ readonly action: _angular_core.InputSignal<((value: TSubmit) => Promise | MdyFormError[] | void) | undefined>; /** * Default values for declarative mode. * Per-control [initialValue] takes precedence over this. */ readonly formValue: _angular_core.InputSignal> | undefined>; /** Submit behaviour for declarative mode (ignored when adapter is provided). */ readonly submitMode: _angular_core.InputSignal; /** * Form-level (cross-field) validators for declarative mode. Build them * with `crossField()`; errors land on the involved fields (or on the form * with `path: null`). With `[form]`/`[adapter]` declare validators on the * model instead. */ readonly formValidators: _angular_core.InputSignal>[]>; /** * Declarative-mode draft autosave: persists the form value under this key * (localStorage) and restores it on init; cleared after an error-free * submit. With `[form]`/`[adapter]` configure the draft on the model. */ readonly draftKey: _angular_core.InputSignal; readonly submitted: _angular_core.OutputEmitterRef>; private readonly _declarativeAdapter; /** Last seed applied from [formValue] — used to diff per key (B2). */ private _lastSeed; /** One-shot guard for the registry-incompatible [adapter] dev warning. */ private _warnedAdapterRegistry; constructor(); /** Where the deferred draft start is scheduled from; the constructor is an injection context. */ private readonly _draftInjector; claimField(name: string): void; removeField(name: string): void; /** Active adapter: [adapter] wins, then [form], then the internal one. */ private get _active(); /** * Registry target for controls/directives. Must resolve to the same object * as {@link _active}: claims and validators registered on a different * adapter than the one whose value is displayed would silently diverge * (required not applied, wrong field released on destroy). */ private get _registry(); addValidators(name: string, validators: ReadonlyArray>, isRequired?: boolean): void; upsertValidators(name: string, key: string, validators: ReadonlyArray>, marksRequired?: boolean): void; removeValidators(name: string, key: string): void; upsertAsyncValidators(name: string, key: string, validators: ReadonlyArray>, options?: MdyAsyncValidatorOptions): void; setInitialValue(name: string, value: unknown): void; setSanitizer(name: string, sanitizer: MdySanitizer): void; setDisabled(name: string, disabled: Signal): void; setInactive(name: string, inactive: Signal): void; setReadonly(name: string, readonly: Signal): void; get state(): MdyFormState; /** Class vocabulary for the form's own parts, from the widget contract rather than spelled here. */ protected readonly formErrorsClass: string; protected readonly formErrorItemClass: string; /** What the form has to say about itself: the refusals no field will show. */ protected formErrors(): ReadonlyArray; /** * Reactive flat field paths of the active adapter — used by the devtools. Empty for a custom * `[adapter]` with no notion of membership to report. */ get fieldNames(): Signal; get value(): Signal; getValue(): T; /** Every field except the disabled ones — what a submit actually sends. */ submitValue(): TSubmit; getField(name: K): MdyFieldRef | null; errorsFor(path: keyof T | string): Signal>; submit(action: (value: TSubmit) => Promise | MdyFormError[] | void): Promise; markAllTouched(): void; /** Forwarded like every other adapter member: the form the component wraps is the one that counts it. */ reportEntry(name: string, problem: string | null): void; buildSubmitEvent(value: TSubmit): MdyFormSubmitEvent; patchValue(partial: Partial): void; setValue(value: T): void; reset(): void; protected handleSubmit(): Promise; static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; static ɵcmp: _angular_core.ɵɵComponentDeclaration, "mdy-form", never, { "adapter": { "alias": "adapter"; "required": false; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "action": { "alias": "action"; "required": false; "isSignal": true; }; "formValue": { "alias": "formValue"; "required": false; "isSignal": true; }; "submitMode": { "alias": "submitMode"; "required": false; "isSignal": true; }; "formValidators": { "alias": "formValidators"; "required": false; "isSignal": true; }; "draftKey": { "alias": "draftKey"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; }, never, ["*"], true, never>; } /** * Marks an `` as inspectable by the devtools overlay: * * ```html * * ``` * * Press the hotkey (default **Ctrl+Shift+D**, see `MDY_DEVTOOLS_HOTKEY`) to * toggle a draggable overlay inspecting the form that currently has focus * (fallback: the last registered form). Close it with ✕ or Escape. */ declare class MdyDevtoolsDirective { constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Floating, draggable window around the devtools panel — opened by * {@link MdyFormsDevtoolsService} via a keyboard shortcut. Drag it by the * title bar; the ✕ button (or Escape while it has focus) closes it. */ declare class MdyFormsDevtoolsOverlayComponent { readonly form: _angular_core.InputSignal; readonly closed: _angular_core.OutputEmitterRef; private readonly _offset; protected readonly translate: _angular_core.WritableSignal; private _dragging; private _start; protected onDragStart(event: PointerEvent): void; protected onDragMove(event: PointerEvent): void; protected onDragEnd(event: PointerEvent): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } interface DevtoolsFieldRow { readonly path: string; readonly value: string; readonly valid: boolean; readonly touched: boolean; readonly dirty: boolean; readonly pending: boolean; readonly errors: readonly string[]; } /** * Live inspector for a form model — the universal "why is my form * invalid?" debugging pain, answered in one panel. * * ```html * @if (isDevMode) { * * } * ``` * * Shows the live value (JSON, `File`s serialized), the form state signals * (valid/pending/submitting/submitCount/canSubmit), the last submit errors * and a per-field row (value, valid/touched/dirty/pending, error messages * with their origin) for every handle passed in `[fields]`. Values of * sensitive-looking fields (password, token, card…) are masked; add more * paths via `[maskFields]`. Render it behind `isDevMode()` — it ships no * providers, and it is only bundled when your code imports it (standard * tree shaking: unused imports are dropped by the production build). */ declare class MdyFormsDevtoolsComponent { /** The form model to inspect (an `mdyForm()` result or any adapter). */ readonly form: _angular_core.InputSignal; /** * Typed handles to show as per-field rows (`[form.f.email, …]`). * When omitted, the rows are derived automatically from the form's * registered field names. */ readonly fields: _angular_core.InputSignal[]>; /** Start with the body expanded (the overlay opens it this way). */ readonly expanded: _angular_core.InputSignalWithTransform; /** * Extra field paths whose values are masked in the panel, in addition * to the built-in heuristic (paths containing password/token/card/…). */ readonly maskFields: _angular_core.InputSignal; /** * Field paths hidden from the devtools entirely — no row and no key in * the JSON view (masking shows `•••`; excluding shows nothing). */ readonly excludeFields: _angular_core.InputSignal; protected readonly open: _angular_core.WritableSignal; protected readonly nameFilter: _angular_core.WritableSignal; protected readonly onlyInvalid: _angular_core.WritableSignal; protected readonly onlyTouched: _angular_core.WritableSignal; protected readonly onlyDirty: _angular_core.WritableSignal; protected readonly onlyPending: _angular_core.WritableSignal; protected readonly state: Signal<{ valid: boolean; pending: boolean; submitting: boolean; submitCount: number; canSubmit: boolean; }>; protected readonly valueJson: Signal; protected readonly submitErrors: Signal; protected readonly rows: Signal; protected readonly filteredRows: Signal; protected copyText(text: string): void; private _isMasked; private _displayValue; /** * Masks sensitive-looking keys and drops excluded ones in the JSON view. * * A collection is walked like anything else, by the indexed paths its rows occupy: a row's field * is `items.0.password` here exactly as it is in the table above, so one rule answers for both * views. Left as a leaf, an array handed back its rows whole — and a password inside one was * printed in the panel this masking exists to keep it out of. */ private _maskDeep; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * Hotkey that toggles the devtools overlay, as `modifier+…+key` * (`ctrl`, `shift`, `alt`, `meta` plus a single key). Default * `ctrl+shift+d` — note this collides with a built-in browser shortcut * in some browsers (e.g. bookmark-all-tabs); override it when that * matters: `{ provide: MDY_DEVTOOLS_HOTKEY, useValue: "ctrl+alt+i" }`. * Provide `null` (or `""`) to disable the hotkey entirely — the overlay * stays reachable via {@link MdyFormsDevtoolsService.toggle}. */ declare const MDY_DEVTOOLS_HOTKEY: InjectionToken; /** * Registry + launcher for the devtools overlay. `mdyDevtools` on an * `` registers the form; the hotkey (default Ctrl+Shift+D) * toggles a draggable overlay inspecting the **selected** form — the * registered form containing the focused element, or the last registered * one as a fallback. Also usable programmatically via {@link toggle}. */ declare class MdyFormsDevtoolsService { private readonly _appRef; private readonly _injector; private readonly _hotkey; private readonly _registrations; private _overlay; private _listening; private _previousFocus; /** Registers an inspectable form (called by the `mdyDevtools` directive). */ register(element: HTMLElement, form: MdyTypedFormLike): void; unregister(element: HTMLElement): void; /** Opens the overlay on the selected (or given) form; closes it if open. */ toggle(form?: MdyTypedFormLike): void; open(form: MdyTypedFormLike): void; close(): void; /** The registered form containing the focused element, else the last one. */ private _selectForm; private _setupHotkey; private _teardownHotkey; private readonly _onKeydown; private _matchesHotkey; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵprov: _angular_core.ɵɵInjectableDeclaration; } declare class MdyDynamicFormComponent { protected readonly defaultFormat: MdyTimeFormat; protected readonly initialView = "dial"; /** The palette the contract suggests, for a document that names none. */ protected readonly defaultPresets: readonly string[]; /** An options field's own members, read from the union the template narrows by `kind`. */ protected asOptions(field: MdyDynamicField): { readonly searchable?: boolean; readonly reorderable?: boolean; readonly mode?: "single" | "multi"; }; /** * The rest of what a document may say about a field, read from the union the template narrows by * `kind`. * * A member a document declares, a component reads and a case does not bind is a capability that * parses, validates and reaches no control — the shape that left `searchable` dropped and a * document asking for a filter getting a native chooser. These are the ones the audit found. */ protected asMore(field: MdyDynamicField): { readonly presets?: readonly string[]; readonly accept?: string; readonly multiple?: boolean; readonly minDate?: string; readonly maxDate?: string; }; /** A timepicker's own members, read from the union the template narrows by `kind`. */ protected asTime(field: MdyDynamicField): { readonly format?: MdyTimeFormat; readonly viewMode?: MdyTimepickerViewMode; readonly granularity?: MdyTimeGranularity; readonly animateHand?: boolean; readonly showUnavailable?: boolean; }; /** * Serializable field configs, rendered in order. * * Optional because {@link MdyDynamicFormComponent.document} is the other way in. One of the two is * given; a component handed neither renders nothing, which is what an empty list already meant. */ readonly fields: _angular_core.InputSignal; /** * A document as it arrived — from a server, a CMS, a model — read by this component. * * The component is named for the dynamic contract and took only the *parsed* half of it, so a host * rendering one server document on this adapter and another wrote the parse step twice, with the * strict-mode diagnostics and the refusal of a partial form as the part most easily forgotten. * * Untrusted by construction: it is parsed here, and in strict mode a document carrying any error * renders nothing rather than the part of itself that happened to be well formed. The diagnostics * are emitted either way, so a host can show them. */ readonly document: _angular_core.InputSignal; /** * What tells this form's ids apart from another form's built from the same document. * * Ids come from the field's path, so two forms of one document claim one set of them (ADR 0135). * A consumer placing controls by hand scopes each of them; a consumer of this component places * none — it builds its own — so the scope is taken here, at the door a document arrives through, * and forwarded to every control this form renders. */ readonly idScope: _angular_core.InputSignal; /** * This instance's identity, for the scope registry to key on. * * An empty object, held for the component's lifetime. What the registry needs is something that is * *this form and no other* — the component itself would do, and an object with no other purpose * cannot acquire one. */ private readonly scopeIdentity; /** * The scope actually used: the one bound, or one derived when nothing was bound. * * The comment on `idScope` has always said the scope is taken here, at the door a document arrives * through. It was not: the default was empty, so two of these on one page claimed one set of ids * and every reference in the second resolved into the first — a person using a screen reader in the * second form heard the help text of a field they were not looking at. The page shows nothing and * nothing throws: it is answering a different question correctly. * * Derived the way the framework-free renderer derives it, from the same primitive, so a document * behaves the same whichever renderer draws it. Only a *live* scope pushes the next one along, so a * form that has gone takes its scope with it and the form that replaces it reads as the one before. * * A consumer binding `idScope` still decides: this fills the silence, it does not overrule. * * **Asked of the live set rather than of the document**, which is the difference between here and * the framework-free renderer. There, mounting is a call and the first form has written its ids * before the second asks. Here both are computed in one change-detection pass, before either has * rendered anything — so a form looking for its neighbour's ids in the DOM finds an empty page and * takes the same scope. The component knows what is live at a moment the document does not. */ protected readonly resolvedScope: Signal; /** * Where this form keeps what has been typed but not sent, and `undefined` for a form that keeps * nothing. * * Forwarded to the inner form rather than declared again. The other renderers of a document take * the same option at their own door, and a component that accepted a document and dropped this * silently was a form asked to keep a draft that kept nothing and said nothing about it. */ readonly draftKey: _angular_core.InputSignal; /** How the document is read. `strict` refuses a document with any error; `lenient` renders what parsed. */ readonly parseMode: _angular_core.InputSignal; /** What reading {@link MdyDynamicFormComponent.document} found, emitted whenever the document changes. */ readonly diagnostics: _angular_core.OutputEmitterRef; /** * The document, read — or `null` when none was given and the pre-parsed inputs are the source. * * A computed rather than an effect: the fields and the layout are two readings of one parse, and * parsing once per read of each would answer two different documents for one input. */ protected readonly parsed: Signal<_modyra_core.MdyDynamicFormParseResult | null>; /** * What is rendered: the document's fields when there is one, the input's otherwise. * * The input's are checked, because nothing upstream has checked them. A document arrives through a * parser that drops what the contract will not carry; a field list handed over directly arrives as * it was written, and a list naming one field twice built a form with one of that name and a * control for each — so the second control wrote into the first control's field, over what a person * had typed, and the entry after the pair was not drawn at all. The check is the same one the other * renderer's field-list door makes, and it refuses rather than repairs: which of two fields sharing * a name is the real one is not something a renderer can know. */ protected readonly renderedFields: Signal; /** The layout the same way, so a document that is refused arranges nothing either. */ protected readonly renderedLayout: Signal; /** * What a field starts as when the config names no initial value. * * The answer is the contract's, not this template's: spelling it per kind here made a third table * beside the one the rule reads, and the three did not agree. */ protected emptyFor(field: MdyDynamicField): unknown; /** * Contract v2 layout: sections and column rows, nestable. Fields the layout names render inside * it; anything it does not mention still renders, after — a partial layout arranges the part it * describes rather than hiding the rest. */ readonly layout: _angular_core.InputSignal; /** The class vocabulary is the contract's, so every adapter draws the same grid. */ protected readonly layoutClasses: Readonly<{ section: "mdy-layout-section"; sectionLabel: "mdy-layout-legend"; columns: "mdy-layout-columns"; column: "mdy-layout-column"; }>; /** Fields no layout node claims, rendered after the arranged ones. */ protected readonly unplacedFields: Signal; /** * The field a slot names, or `null` when the child is a nested layout node. * * A bare string and a v3 `{ ref }` slot name a field the same way; the slot merely also says where * it sits. Answering with the name rather than a type guard keeps the template to one branch for * both spellings, which is what stops the two drifting apart. */ protected fieldNameOf(child: MdyDynamicLayoutChild): string | null; /** * A column's own placement, from the first child inside it that asks for one. * * A slot and a section answer the same way: a section occupying a column is a column like any * other, which is how a group in a row is laid out for a screen size. */ protected columnStyle(column: ReadonlyArray): Record; protected fieldByName(name: string): MdyDynamicField | undefined; /** The track count the foundation divides a column row by. */ protected columnRowStyle(node: MdyDynamicLayoutNode): Record; /** Re-emitted from the inner ``. */ readonly submitted: _angular_core.OutputEmitterRef, Partial>>>; /** Inner form — exposed so consumers can call getValue()/reset()/submit(). */ readonly form: Signal, Partial>>>; private readonly _injector; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * One step of an ``. * * The step declares which fields it owns via `[fields]` (names or typed * handles): the wizard gates navigation on their validity and marks them * touched when the user tries to advance past an invalid step. * * Inactive steps are hidden, **not destroyed** — their controls stay * registered on the form, so values and validators survive navigation. */ declare class MdyWizardStepComponent { /** Step title shown in the wizard progress header. */ readonly label: _angular_core.InputSignal; /** * Fields owned by this step — names (`"email"`) or typed handles * (`form.f.email`). Used for per-step validation. */ readonly fields: _angular_core.InputSignal)[]>; /** Resolved adapter paths of the step's fields. */ readonly fieldNames: Signal; /** Set by the parent wizard. */ readonly isActive: _angular_core.WritableSignal; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * Multi-step wizard over a single ``. * * Place it inside the form and declare the steps as content children; the * wizard shows one step at a time (hidden, not destroyed), gates "Next" on * the validity of the active step's `[fields]`, and renders a progress * header plus navigation buttons. * * ```html * * * * * … * * * * * ``` * * `finished` fires on the last step's confirm button — typically you call * `form.submit(...)` or submit the surrounding form there. */ declare class MdyFormWizardComponent { protected readonly i18n: _modyra_widgets.MdyI18nMessages; private readonly adapter; protected readonly steps: Signal; private readonly _activeIndex; /** Index of the currently visible step. */ readonly activeIndex: Signal; /** True while the last step is active. */ readonly isLast: Signal; /** 0..1 progress across the steps (for progress bars). */ readonly progress: Signal; /** Validity of the currently active step's declared fields. */ readonly activeStepValid: Signal; /** Fires after every successful navigation with the new index. */ readonly stepChange: _angular_core.OutputEmitterRef; /** Fires when the user confirms the last step. */ readonly finished: _angular_core.OutputEmitterRef; constructor(); /** Advances (or fires `finished` on the last step) if the step is valid. */ next(): void; previous(): void; /** Jumps to a step: backwards freely, forwards only across valid steps. */ goTo(index: number): void; /** True when every step before `index` is valid. */ protected canJumpTo(index: number): boolean; private _stepValid; private _touchStep; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * Chips Directive to enhance select/multiselect options. * * Provides Material 3 styling and behavior for "Input Chips" or "Filter Chips". */ declare class MdyChipsDirective { /** * What the chip wears, from the contract's vocabulary rather than from three literals here. * * A class spelled in a template is a renderer deciding what a chip is; the next one spells it * differently, and the theme's rule quietly styles nothing. */ protected readonly classes: _angular_core.Signal; /** Whether the chip is currently selected/active. */ readonly selected: _angular_core.InputSignal; /** Whether the chip shows a removal (X) icon. */ readonly removable: _angular_core.InputSignal; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Directive that automatically filters options of a host select/multiselect * based on the value of another field in the same form. * * Usage: * ```html * * * ``` */ declare class MdyConditionalOptionsDirective { /** Name of the form field that this control depends on. */ readonly mdyDependsOn: _angular_core.InputSignal; /** * Map of options keyed by the dependent field's value, * or a function that returns options given the value. */ readonly mdyOptionsMap: _angular_core.InputSignal[]> | ((val: unknown) => readonly MdySelectOption[])>; private readonly adapter; private readonly host; /** Sentinel distinguishing "no previous run" from a legitimate undefined value. */ private static readonly UNSET; private previousVal; constructor(); static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration, "[mdyDependsOn]", never, { "mdyDependsOn": { "alias": "mdyDependsOn"; "required": true; "isSignal": true; }; "mdyOptionsMap": { "alias": "mdyOptionsMap"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>; } /** * Optional wrapper component for form controls. * * Provides a styled container with data-field attribute. * Error display is handled by each renderer component directly. * * Usage: * ```html * * * * ``` */ declare class MdyControlComponent { readonly name: _angular_core.InputSignal; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * Marks a template or element as an input prefix (leading content). */ declare class MdyPrefixDirective { readonly template: TemplateRef; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Marks a template or element as an input suffix (trailing content). */ declare class MdySuffixDirective { readonly template: TemplateRef; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Marks a template or element as supporting text (helper text). */ declare class MdySupportingTextDirective { readonly template: TemplateRef; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Abstract base class for all renderer components. * * Injects the nearest MdyFormAdapter (provided by MdyFormComponent) * and resolves the field state by name. Provides convenience computed * signals that concrete renderers bind in their templates. */ declare abstract class MdyBaseControl implements OnInit { protected readonly hostElement: ElementRef; private readonly _destroyRef; private readonly _injector; private prefixObserver?; /** Field name currently claimed on the registry (tracks name changes). */ private _claimedName; constructor(); /** * Field name for declarative (`name`-based) mode. * Optional when a typed `[field]` handle is bound instead. */ readonly name: InputSignal; /** * Typed field handle from an `mdyForm()` schema — the type-safe * alternative to the stringly `name` attribute: * ``. * Accepts the nullable variant too: adapter fields start as `null` * (e.g. Zod-derived handles are `T | null`) and every renderer already * treats `null` as "empty". The control only reads the handle's path. */ readonly field: InputSignal | MdyFieldHandle | undefined>; /** Resolved adapter path: the handle's path or the `name` input. */ protected readonly effectiveName: Signal; /** * Which form on the page this control belongs to, where a host renders more than one. * * Unset is the ordinary case. Set, it scopes every id this control publishes, so two forms built * from the same document do not both claim `when__label`. A single character neither part may * contain joins them, so two distinct scopes cannot produce one id. */ readonly idScope: InputSignal; /** What a control with no field falls back to. Not stable across mounts, because nothing about * such a control is. */ private readonly mountId; /** * The id every part of this control is built from. * * Derived from the field's own path (ADR 0135), so the same document renders the same ids every * time: a consumer can write `aria-describedby="when__label"` in their own markup, a stylesheet or * a test can name one, and server-rendered markup agrees with a client mount. A mount counter is a * property of what else was on the page first, and made every one of those a guess. * * Two fields called `when` on one page collide, visibly, and that is the better failure: two * counters never collide and never mean anything either. `idScope` is what a host with two forms * uses to keep them apart. */ protected get fieldId(): string; /** The label text for the form control. */ readonly label: InputSignal; /** * The control's name when nothing visible carries it — a cell in a table, a control in a toolbar * whose column or icon says what it is to someone who can see it. * * Read only while `label` is empty. A visible label already names the control natively, and a * second name over the top of it is what makes the spoken name disagree with the written one. */ readonly ariaLabel: InputSignal; /** * The name on the control element. * * The explicit one when it is given, otherwise the visible label's text. Naming the control from * the label as well as through `for` is redundant on paper and load-bearing in practice: the * label element also holds the required marker, so a name computed from its content carries an * asterisk the user's word does not — and anything matching on the name exactly, a test or an * assistive tool's find-by-name, then misses the control the user is asking for. */ /** * What this control is announced as. * * The order is the contract's: a spoken name a document wrote, the visible label, and the field's * own name when there is neither. A control with none of the three is announced as its role and * nothing else — a text box, on a form of them — and the field name is the one thing always * present, so it is a poor name and better than no name. */ protected readonly controlAriaLabel: Signal; /** * Which attribute names this control, asked of the contract rather than answered per renderer. * * Two names on one element is not two names: the computation takes `aria-labelledby` and stops, so * an `aria-label` beside it is text nobody hears — and a renderer writing `aria-label` where the * field has a visible caption replaces the words a person is reading with words only a reader * hears. ADR 0175. */ protected readonly namedBy: Signal>>; /** Opt-in or opt-out of floating labels on a per-control basis, overriding the form-level directive. */ readonly floatingLabel: InputSignal; /** * Optional initial value for declarative mode. * Takes precedence over [formValue] set on the parent . */ readonly initialValue: InputSignal; /** * The form this control writes into. * * Injected optionally so the failure can name the control. Without a form above it, Angular's own * error reports the missing token and nothing else — true, and useless in a template with thirty * controls in it, because the one that is outside is exactly the one it does not name. */ private readonly _adapterOrNull; private get adapter(); /** What identifies this control in a message, when it has said anything about which field it is. */ private _nameForError; private readonly _declarativeRegistry; /** True when MdyInlineErrorsDirective is applied to this element. */ protected readonly inlineErrors: boolean; private readonly globalFloatingLabels; /** Marks the field as required for assistive technology. */ readonly ariaRequired: InputSignal; /** Marks the field as disabled for assistive technology (auto-derived from field state). */ readonly ariaDisabled: InputSignal; /** Leading content (icon/text) provided via `mdyPrefix` directive. */ protected readonly prefix: Signal; /** Trailing content (icon/text/button) provided via `mdySuffix` directive. */ protected readonly suffix: Signal; /** Supporting text (helper text) provided via `mdySupportingText` directive. */ protected readonly projectedSupportingText: Signal; /** * The line under the control, as a value rather than a projected template. * * Projection is how a hand-written host supplies it; this is how a **document** does. A field * declaring `supportingText` had no route to the slot in this adapter, so the words existed in the * contract and reached three renderers of four. */ readonly supportingText: InputSignal; /** Whether anything at all wants the description slot — either route. */ protected readonly hasSupportingText: Signal; /** * Inert state served while `name`/`[field]` are still unresolved. Input * signals are not set during construction, so any computed chained to * {@link fieldState} (value, errors, …) must stay readable there instead * of throwing; the constructor effect reports controls that are STILL * unresolved after init. Per instance — never shared. */ private _detachedState?; private _detached; /** * The form that built the bound handle, when it is one this library made and it is not the form * enclosing this control. `null` for a `name` binding, a hand-built handle, or the ordinary case * of a handle from the enclosing form. */ private _formOfHandle; /** Resolved field state — reactive to name/[field] changes. */ protected readonly fieldState: Signal>; readonly value: Signal; /** * The errors this control shows — which is not always the errors the field holds. * * A field the form is not asking about carries no verdict on screen: the rule belongs to * `@modyra/widgets`, and everything below reads it from here, so the wrapper class, the label * state, `aria-invalid` and the error list cannot drift apart. The devtools panel deliberately * reads the field instead: a debugging view shows the model, not what the user is being asked. */ protected readonly errors: Signal>; protected readonly touched: Signal; protected readonly dirty: Signal; protected readonly isDisabled: Signal; /** * Read but not written. * * Angular had no counterpart to `isDisabled`, so no template could bind the native attribute and * a field a form had marked read-only kept accepting typing. `dispatchValueIntent` already fed * `readonly` to the scalar controller, which meant the blocking half worked while the DOM said * nothing — the confusing state this closes. */ protected readonly isReadonly: Signal; protected readonly isValid: Signal; protected readonly hasErrors: Signal; /** * The messages a person is reading right now, which is not the same list as the ones that exist. * * `errors` answers *which refusals there are*; this answers *whether they are being told yet*, and * a renderer painting a list is asking the second. Bound to the first, every kind printed * "required" under a field nobody had answered — while `aria-invalid` beside it said `false`, * because that one had been taught the rule and this had not. One field, two verdicts, and the one * a sighted person reads was the wrong one. * * The container stays reserved either way: a message arriving must not push the page down. */ protected readonly errorsOnScreen: Signal>; /** * Whether the control announces itself as failing — the one answer for `aria-invalid`. * * Named for the question because eight templates were answering it and one of them answered * differently: the colours field waited for `touched`, so a screen-reader user met a control the * form was rejecting and the control said nothing was wrong. The rule is the contract's * (`showsAsInvalid`: out of play, no verdict), and `errors()` already withholds the errors of a * field the form is not asking about — so a template that spells its own combination is a * template that can disagree with both. */ protected readonly paintsAsInvalid: Signal; /** * The classes on the wrapper that holds the control, which is where a field shows it is unusable, * locked or wrong. * * Composed here from the contract's own table rather than spelled per template. Every renderer * wrote the base class and bound `--disabled` beside it, and none of them bound the other two the * contract lists: a field the form had refused looked exactly like one it had accepted, and a * field locked for review exactly like one waiting to be filled in. The error class follows * `paintsAsInvalid`, the same answer `aria-invalid` takes, so what a theme paints and what a * screen reader is told cannot disagree. */ protected readonly wrapperClasses: Signal; /** * Where the keyboard goes when this field leaves play under it. * * Disabling a focused element blurs it — that is the platform. What follows is this library's: the * person who was typing is on ``, their next Tab starts at the top of the document, and * nothing says where they went. A document's rule reaches this without anyone clicking, when a * value arriving from a fetch takes the field under the cursor out of play mid-word. * * `relatedTarget === null` is the only case handled: focus went nowhere rather than to something * else on the page. It is read one microtask later because the control is disabled during the * render that blurs it, and the question is what happened after. */ protected onFocusLost(event: FocusEvent): void; /** Effective aria-disabled: explicit input overrides field state. */ protected readonly effectiveAriaDisabled: Signal; /** * Whether the error list is actually in the DOM. * * The single condition every renderer template guards the list with, so that anything naming the * list — `aria-describedby` above all — cannot disagree with whether it was rendered. An invalid * but untouched field is the common case: it has errors and shows none. */ /** * Whether the error list is in the DOM, whether or not it holds a message. * * What the templates guard on. The container is reserved under any field that can fail a rule, * because one that appears with the first message pushes down the field below it — the field * somebody leaving is moving toward, at the moment they are already moving. It stays once a message * clears: taking the space back is the same jump, upward. * * Distinct from {@link errorsRendered}, which stays "there is something to show". Supporting text * is displayed when no errors are, and folding the two together would hide the help at rest under * every field with a rule — an error must not take the place of the instruction that prevents it. */ protected readonly errorsReserved: Signal; protected readonly errorsRendered: Signal; /** * The same question for a renderer that draws its error text beside the control rather than in a * list below it. One of the two is true at a time; both read the one rule, so a renderer cannot * show text the other would have hidden. */ protected readonly inlineErrorShown: Signal; /** * The id the supporting-text element carries, or `null` when none is rendered. * * Bound as `[id]` on that element by every renderer that draws one. Without it the text is * rendered, styled, and announced to nobody: a description no reference can reach is invisible to * assistive technology however carefully it is worded. */ protected descriptionId(fieldId: string): string | null; /** * The id for `aria-describedby`, or `null` when there is nothing rendered to name. * * Takes the renderer's own `fieldId`, since each renderer mints one. The error list wins where * there is one, the supporting text answers otherwise, and a control with neither describes itself * by nothing — never by an id no element holds. */ protected describedById(fieldId: string): string | null; /** * The semantic state of this control, as the shared contract projects it. * * A renderer binding `[mdyPart]="controlPart()"` receives `aria-invalid`, `aria-required`, * `aria-disabled` and `aria-describedby` from the shared projection, so no renderer decides for * itself which of a widget's states to expose. * * `errorsVisible` is answered here because the projection cannot know it: these renderers defer * the error list until the field is touched, so having errors is not the same as showing them. */ /** * The values a native submit reads, for the kinds that draw no form control at all. * * A select is a button and a listbox; a multiselect is a button and a strip of chips. Neither is * something a form serialises, so without these inputs the browser sends nothing for the field — * not an empty value, nothing. Which kinds need them is the contract's answer, not this file's. */ private syncHiddenSubmission; /** * The name a group of radio inputs shares. * * Two jobs in one attribute — it groups the set, and it is the key the answer arrives under — and * which one is at stake depends on whether this control has a form to belong to. Read from the DOM * rather than from state, because that is where the answer lives. */ protected groupName(): string; /** * The hidden input a boolean field renders ahead of its box. * * HTML leaves an unchecked box out of the payload altogether, so without this a person who said no * and a form that never carried the question arrive identical at the other end. It carries `false` * under the field's key; when the box is checked it sends `true` after this one, and the later * value is the answer. */ protected readonly submitFalsePart: Signal; protected readonly controlPart: Signal; /** * The kind this renderer draws. * * The projection decides from it which native constraints the control can carry, so a renderer * that does not say leaves a slider claiming `maxlength` and offering no range. It was typed * `string` and defaulted to text, which is how nine renderers came to inherit an answer none of * them meant; the union is what makes a wrong one unspellable. */ protected readonly widgetKind: MdyWidgetKind; /** * What this renderer asks for on top of the field's rules — nothing, unless it has its own limits * to state. It cannot ask for more: the projection takes whichever end is tighter. */ protected narrowedConstraints(): Partial; /** Whether the field is required (deduced from validators). */ protected readonly isRequired: Signal; /** Error messages joined as a single string for inline display. */ protected readonly inlineErrorText: Signal; /** Whether the field should display a floating label. */ protected readonly isFloatingLabel: Signal; private readonly _valueControllers; /** * Sends scalar UI transitions through Widgets. Angular remains responsible * only for extracting the native DOM value and applying controller commands * to the form adapter. */ protected dispatchValueIntent(kind: MdyWidgetKind, intent: MdyValueWidgetIntent): void; /** * The kind's own controller, built the first time this renderer needs it. * * Deferred rather than built in `ngOnInit`, because a field initializer is an injection context * and `ngOnInit` is not — and because six renderers each writing the same lifecycle is the * duplication that adopting a shared controller was supposed to remove, not relocate. */ protected adoptFieldController(create: (handle: MdyFieldHandle, widgetId: string) => TController, sync?: (controller: TController) => void): () => TController | undefined; /** * A handle for the control to build its controller on, however the field was named. * * `[field]` hands one over. The `name` form does not — it resolves to the registry's state — and * for want of a handle every renderer kept a second way to commit its value, so the kind's * controller decided for one caller and the renderer decided for the other. The state carries * everything a handle exposes; what was missing was the shape, and the shape is written once. * * Registered against Angular's own runtime, because a controller resolves the runtime that owns * its handle: a synthetic one nobody claims would be observed by a vanilla runtime that cannot * see an Angular signal, and would render once and then never again. */ private _syntheticHandle; private controllerHandle; protected dispatchValueBlur(kind: MdyWidgetKind): void; /** * The touched and dirty callbacks a widget runtime takes, answered by the owner of the value. * * A renderer that answers them itself has taken a decision the controller exists to make, and the * next renderer will not take it the same way. The runtime asks; this is who it reaches. */ protected valueOwnerCallbacks(): { readonly onTouched: () => void; readonly onDirty: () => void; }; /** Applies non-user synchronization without dirty/touched side effects. */ protected synchronizeValue(value: TValue): void; setValue(newValue: TValue): void; protected markAsTouched(): void; protected markAsDirty(): void; /** * An entry the control could not read, said to the form. * * Resolved against the same form the state came from — a path means nothing without its form — * and silently ignored when the control is not bound, which is the state a detached control is in * before its name resolves. */ protected reportEntry(problem: string | null): void; /** Generate a unique ID for template label/input association. */ protected static nextId(): number; ngOnInit(): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration, never>; static ɵdir: _angular_core.ɵɵDirectiveDeclaration, never, never, { "name": { "alias": "name"; "required": false; "isSignal": true; }; "field": { "alias": "field"; "required": false; "isSignal": true; }; "idScope": { "alias": "idScope"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "floatingLabel": { "alias": "floatingLabel"; "required": false; "isSignal": true; }; "initialValue": { "alias": "initialValue"; "required": false; "isSignal": true; }; "ariaRequired": { "alias": "ariaRequired"; "required": false; "isSignal": true; }; "ariaDisabled": { "alias": "ariaDisabled"; "required": false; "isSignal": true; }; "supportingText": { "alias": "supportingText"; "required": false; "isSignal": true; }; }, {}, ["prefix", "suffix", "projectedSupportingText"], never, true, never>; } /** * Block error list displayed below a form control. * * Renders a `
    ` of validation error messages. Used when * `mdyInlineErrors` is **not** applied to a renderer. * * ```html * * ``` */ declare class MdyErrorListComponent { readonly fieldId: _angular_core.InputSignal; readonly errors: _angular_core.InputSignal; /** * The id comes from the shared factory rather than a local string, so that everything naming this * list — a projection's `aria-describedby` included — resolves to the element actually rendered. * Two spellings of one relation is how a reference silently dangles. */ protected readonly errorsId: _angular_core.Signal; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * Inline error icon with hover/focus tooltip. * * Renders a warning triangle SVG that reveals the error message on * hover or keyboard focus. Used inside labels when `mdyInlineErrors` * is applied to a renderer. * * ```html * * ``` */ declare class MdyInlineErrorIconComponent { readonly errorText: _angular_core.InputSignal; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * Attribute directive that switches a renderer to inline error display. * * When applied to a renderer component, errors are shown in parentheses * next to the label instead of as a block below the input. * * ```html * * ``` */ declare class MdyInlineErrorsDirective { static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵdir: _angular_core.ɵɵDirectiveDeclaration; } /** * Shared label + optional inline-error-icon block. * * Eliminates the duplicated `@if (label()) { }` pattern * that was copy-pasted across every renderer component. * * ```html * * ``` */ declare class MdyControlLabelComponent { /** The label text. If empty, renders nothing. */ readonly label: _angular_core.InputSignal; /** * Whether the field this label belongs to is failing. * * Distinct from `showInlineError`, which says *where* the message is drawn. The label used to take * its state from that alone, so a field showing its errors in a list below — the default — had a * label that never marked itself, and a theme keying off the class painted nothing on the field * the form had refused. */ readonly hasError: _angular_core.InputSignal; /** The `id` of the input this label is associated with (maps to `[for]`). */ readonly forId: _angular_core.InputSignal; /** * Optional `id` rendered on the `