import { type MdyWidgetKind } from "./catalog.js"; /** Every state any widget may declare. */ export declare const MDY_WIDGET_STATES: readonly ["pristine", "touched", "empty", "filled", "invalid", "disabled", "readonly", "open", "focused", "selected", "loading"]; export type MdyWidgetState = (typeof MDY_WIDGET_STATES)[number]; /** * What a state means for the DOM, independent of kind. * * `nativeAttribute` is the point of the whole exercise. A renderer that flips only `aria-disabled` * leaves the native control focusable and editable: assistive technology is told one thing and the * keyboard does another. The contract has to separate *the semantic state exposed* from *the * behavioural state in effect*, and only a matrix can check that they agree. */ export interface MdyWidgetStateContract { /** The ARIA attribute that must carry this state, and the value it must carry. */ readonly aria?: { readonly attribute: string; readonly value: string; }; /** The native attribute that must be applied to the control, not merely mirrored in ARIA. */ readonly nativeAttribute?: string; /** Parts the contract requires to exist in this state. */ readonly requiresParts?: readonly string[]; /** Parts that must NOT exist in this state. */ readonly forbidsParts?: readonly string[]; /** * What the state means for the *form*, as against the DOM. * * Two states can render almost identically and behave completely differently — `disabled` and * `readonly` differ in whether the field is sent and checked at all. A contract describing only * attributes cannot express that, because nothing about the markup distinguishes them. */ readonly behaviour?: { /** Whether a field in this state is included in what a submit sends. */ readonly submitted: boolean; /** Whether a field in this state is validated. */ readonly validated: boolean; /** Whether the user can still reach the control: focus it, select its text, copy it. */ readonly reachable: boolean; }; } export declare const MDY_WIDGET_STATE_CONTRACTS: Readonly>; /** * The parts `kind` must expose `state` on, or empty where the state carries no ARIA. * * Empty is an answer with two meanings the caller must keep apart: a state with no ARIA at all * (`focused`, `selected`) and a state this kind does not support. `widgetSupportsState` settles the * second before this is asked. * * Returns part *names*: the table above is what is typed against each kind's anatomy, so a name that * is not a part of the kind it is declared under is a compile error there, where it is written. */ export declare function stateCarriers(kind: MdyWidgetKind, state: MdyWidgetState): readonly string[]; export declare const MDY_WIDGET_STATE_SUPPORT: Readonly>; /** * The parts that belong to the open overlay rather than to the resting widget. * * The static and the dynamic contract were conflated: `datepicker` and `daterange` mount their * grids and overlays while *closed*, which is predictable but costly on a large form, and — worse * for a specification — left no way to say whether that was required or merely what today's * renderers happen to do. * * Splitting it says: these parts are the *open* contract. A closed widget is not required to render * any of them, so a renderer that later mounts its overlay lazily is not breaking the contract, and * one that mounts eagerly is not breaking it either. What both must do is render them when open. * * Read together with a node's `optional`, which is a statement about a part's place rather than about * the widget's whole lifetime: six kinds declare a required part inside an optional `popup`, and the * two are consistent only under that reading — required *while its parent is on the page*. * * The same question as {@link dynamicParts}, and now the same answer. This walked the anatomy itself, * rooting on the part *named* `popup` where the other roots on the part whose *element is* `popup`; * the two agreed on all seventeen kinds only because every popup-element part happens to sit inside * the one called `popup`. Two derivations of one rule can only be kept honest by luck, and the other * is the one with the fixed-point walk and the test that runs it over unordered anatomies. */ export declare function overlayOnlyParts(kind: MdyWidgetKind): readonly string[]; /** * How a kind shows that it is unusable or wrong — the visual half of `disabled` and `error`. * * Two mechanisms are in use and both are legitimate: * * - **`"class"`** — a modifier on the field's wrapper, `mdy-input-wrapper--disabled`. Ten kinds, * every one whose wrapper *is* `mdy-input-wrapper`. * - **`"structural"`** — a theme rule that reaches the state through the DOM instead, because the * kind's wrapper is its own (`mdy-checkbox`, `mdy-slider-container`, `mdy-radio-group`…) and the * native control below it already carries the truth: `.mdy-checkbox__control:disabled + * .mdy-checkbox__indicator`, `:has([aria-invalid="true"])`. * * Declared rather than inferred, and this is the point of the table. `widgetStateClasses` — what the * style audit compares a theme against — can only see the first mechanism, so for the seven kinds * using the second, half the expression of "this field is unusable" sat outside everything this * repository checks. An audit that cannot see a mechanism cannot tell a kind that *shows* it is * disabled from one that merely claims to. * * Giving those seven wrappers `disabled`/`error` state classes instead would be the wrong fix twice * over: it mints seven classes no theme paints, and it contradicts `statesFor`'s rule that a part * redeclaring its class to something different does not inherit the shell's states. * * **This declares what a kind is expected to do, not what the themes were found doing.** `file` * says `"structural"` and no theme currently reaches it at all — that is the declaration working: * the gap is reported instead of being written down as intended. */ export declare const MDY_STATE_EXPRESSION: Readonly>; /** Whether a kind declares a state. */ export declare function widgetSupportsState(kind: MdyWidgetKind, state: MdyWidgetState): boolean; /** How many kind × state pairs the contract declares — the matrix's size. */ export declare function widgetStateMatrixSize(): number;