/** * Runtime DOM conformance. * * The static audits in `scripts/` prove that an adapter *references* the contract; this proves * that what it actually rendered matches it. It takes real elements, so any adapter — in a test * harness, in jsdom, in a browser — is held to the same gate. */ import { type MdyWidgetKind, type MdyWidgetVariant } from "../catalog.js"; export type MdyDomContractIssueCode = "EXEMPTION_ACTIVE" | "ROOT_CLASS_MISSING" | "ABSENT_PART_NOT_OPTIONAL" | "ABSENT_PART_PRESENT" | "PART_MISSING" | "PART_CARDINALITY" | "PART_ELEMENT" | "PART_CLASS_MISSING" | "PART_NOT_CONTAINED" | "PART_ORDER" | "ARIA_DANGLING_REF" | "ARIA_AMBIGUOUS_REF" | "ARIA_FOREIGN_REF" | "ARIA_STATE_INCOHERENT" | "ARIA_STATE_NOT_APPLIED" | "ID_DUPLICATE" | "PART_NOT_OWNED" | "ARIA_NON_STRING_STATE" | "RELATION_MISSING" | "RELATION_WRONG_TARGET" | "RELATION_NOT_LABELABLE" | "NAME_MISSING" | "PART_ROLE" | "PART_HIDDEN" | "INVENTED_CLASS" | "STRUCTURE"; export interface MdyDomContractIssue { readonly code: MdyDomContractIssueCode; readonly part: string; readonly message: string; } /** Elements the adapter rendered for each contract part, in document order. */ /** * Whether an element is a part the contract says announces its unavailability rather than setting it. * * Matched by the part's own classes, because that is what an element carries — asking a renderer to * mark it instead would be asking the thing under inspection to describe itself. Exported so the * state matrix asks this question rather than reading the same list a second time: two readings of * one declaration is how two checks come to disagree about it. */ export declare function announcesUnavailability(kind: MdyWidgetKind, element: Element): boolean; export type MdyDomPartMap = Readonly>; export interface MdyDomContractOptions { /** Which element(s) materialize each part. Parts absent from the map are treated as not rendered. */ readonly parts?: MdyDomPartMap; /** * Parts legitimately not rendered in this state — a closed popup, an error list with no errors. * * This is a fixture describing a state, not a silencer. Naming a part the contract declares * mandatory is itself a violation, and so is naming a part that is still in the DOM: an adapter * does not get to decide what the contract requires of it. */ readonly absentParts?: readonly string[]; /** * How many elements each part must have in this state, for parts the contract lets repeat. * The contract knows a part repeats; only the caller knows the state has three options and not * one, so the count comes from here and the *DOM* is what answers it — not the part map, which * is the adapter restating its own claim. */ readonly counts?: Readonly>; /** Reject `mdy-*` classes the contract does not define. A renderer that needs a hook of its own * namespaces it under {@link adapterPrefix} rather than spelling a contract class. */ readonly strictClasses?: boolean; /** * Prefix an adapter uses to namespace classes of its own, such as `mdy--`. * * **Passing this reports `EXEMPTION_ACTIVE` for every class it skips.** It suspends a rule, and a * result that does not say a rule was suspended reads exactly like one where the rule held — while * the person who passed the option and the person who later reads the green are not the same * person. Five undeclared classes lived for months behind this, in a repository whose conformance * check fails on undeclared classes, and the check was green the whole time. * * The option stays because a renderer outside this repository may rely on it. What it no longer * does is stay quiet: either the class is reported as invented, or the exemption is reported as * active. There is no combination that reports nothing. */ readonly adapterPrefix?: string; /** * Whether the widget's overlay is showing. * * A part that only exists inside the popup cannot be required of a closed widget, so the contract * can mark one required and still be satisfied at rest. Left unset, those parts are not demanded: * a caller that has not said which state it is inspecting is not held to the open one. */ readonly open?: boolean; /** * Which configured variant this instance is, for a kind whose anatomy depends on one. * * Left out, a varianted kind is checked only against the anatomy its variants agree on — which is * honest but weak, and is what an inspector that knows nothing about the configuration can say. * Naming it is what makes the differing half checkable. * * Closed: the catalogue declares which configurations exist, so a name nothing describes is a * compile error rather than a widget checked against an anatomy that is not there. */ readonly variant?: MdyWidgetVariant; } /** * What each semantic element in the catalog admits. A part may satisfy its element by tag or by an * explicit role — a `div role="textbox"` is a control, and refusing it would forbid every composite * widget — but it may not satisfy it by carrying the right class and nothing else. A class is * styling; it tells an assistive technology nothing. * * `undefined` means the catalog declares no semantics for that element: a wrapper, a run of text. * Those are listed rather than defaulted, so an element name nobody thought about fails loudly * instead of silently admitting everything. */ export declare const MDY_SEMANTIC_ELEMENTS: Readonly>; /** * The parts of `kind` that carry exactly the classes `part` carries, in declared order. * * Length 1 for almost every part, which is the uninteresting case: the part is alone under its * selector and the first match is it. Where it is longer, the anatomy's order is the only thing * that tells the members apart, and every resolver must read it the same way — two derivations of * "which of these is which" would disagree the moment one of them was tightened. */ export declare function partsSharingClassesWith(kind: MdyWidgetKind, part: string): readonly string[]; /** Pure inspection: returns every way the rendered DOM departs from the contract. */ export declare function inspectWidgetDom(root: Element, kind: MdyWidgetKind, options?: MdyDomContractOptions): readonly MdyDomContractIssue[]; /** Throws one error listing every contract violation found in the rendered DOM. */ export declare function assertWidgetDomContract(root: Element, kind: MdyWidgetKind, options?: MdyDomContractOptions): void;