Ultimate

19.x → 20.0.0, entry by entry

Both entries are @ultimat3/ui component behaviour, and neither changes a type — so nothing fails to compile and nothing throws. They change what a screen DOES, which is why they are a major: a silent rendering change is worse than a build error, and you would have found these by looking.

#SurfaceCosts you an edit if
1DataTable while reloadingyou relied on skeletons appearing on every load. A FIRST load (rows: []) still renders skeletons; a RELOAD now keeps the existing rows, dimmed, under aria-busy. Replacing rendered content with placeholders on every refresh is a second layout change for no news, and it is what makes a fast list feel slow — the reader has already read those rows, and taking them away to say "loading" tells them nothing they can act on. No edit if you pass fresh rows on each load, which is the ordinary case. If you genuinely want the placeholder back on a refresh, pass rows: [] while the fetch is in flight
2Button with loadingyou style button[disabled], or you assert on the disabled attribute in a test. loading no longer sets the native attribute — it sets aria-disabled + aria-busy and refuses the click in onClick with preventDefault(). The click is still refused; the mechanism moved. A disabled control loses focus the moment it becomes disabled — mid-flow, with no announcement — is exempt from the WCAG contrast minimum precisely because nobody is meant to read it, which is wrong for a control you are asking someone to WAIT on, and it does not actually prevent a double submit, because that race is server-side and always was. The edit is one selector: style button[aria-disabled='true'] beside button[disabled], and assert on aria-disabled

defineTheme() can now refuse your brand — X_UI_CONTRAST_INSUFFICIENT. Listed here rather than as a third entry because it throws at declaration with the measured ratio, the required one and the role to move, so it cannot ship silently and needs no search. An override whose RESOLVED channels put a pairing below WCAG 2.2 AA (4.5:1 text, 3:1 focus ring, 1.4:1 border) fails at boot. Only pairings your brand can have CHANGED are measured — blaming an app for the framework's own colours is how a rule gets switched off. The usual defect is half a pairing: a new accent against the shipped white accent-fg. @ultimat3/ui exports contrastRatio and roleContrast so you can measure a candidate before shipping it. AA and never APCA: APCA is not a standard, and AA is the operative legal benchmark.

Nothing else in this release costs an edit. The five new app guards ship in x new only; an existing app gains one with x g guard <name> (since 23.0.0; x doctor --json lists the shipped ones it lacks in data.guards.missing), one file per rule, and deleting one drops that rule. x shot --all-islands is additive, and x g island / x g resource now write a .island.states.ts beside what they generate.

Edit this page on GitHubThis page as markdown