Skip to content
On this page In short

Changelog · latest

@codeatlasdev/ui 2.3.0

13 changes. This release has no written post; the list below is generated from the changelog.

Release 2.3.0Three sketchbook pages stacked and slightly fanned, the front one tabbed with the version number and shaded with pencil hatching in the corner.2.3.0

In short

  1. The generated API reference now documents every non-component expor... The generated API reference now documents every non-component export of every entry point (root, `kit`, `vite`, `astro`, `actions`, `seo`, `forms`, `tokens`, `table`, `charts`): `setLocale`, `registerLocale`, `caErrorPlugin`, `createErrorHandler`, `nativeFeel`, `usePageTitle`, `primeKeyboard`, the stores, the `seo` builders and the types, each with its signature and a JSDoc summary.
  2. New .ca-sr-only utility (visually hidden, still in the accessibil... New `.ca-sr-only` utility (visually hidden, still in the accessibility tree) and `.ca-sr-only--focusable` (shown again while it or a descendant has focus, for skip links).
  3. Add the @codeatlasdev/ui/testing subpath: expectNoA11yViolations... Add the `@codeatlasdev/ui/testing` subpath: `expectNoA11yViolations`, `checkA11y`, `formatViolations`, `settled` and `A11Y_EXCEPTIONS`.

Upgrade

Published under the latest dist-tag.

bun
bash
bun add @codeatlasdev/[email protected]
npm
bash
npm install @codeatlasdev/[email protected]
pnpm
bash
pnpm add @codeatlasdev/[email protected]
yarn
bash
yarn add @codeatlasdev/[email protected]

Then run your checks. Moving between majors? bunx @codeatlasdev/ui migrate --from <major> --to <major> lists what to change, and agents get the same data from the MCP tool get_migration. The migration notes per major are inUpgrading.

Changesets

### Minor Changes

- 1f858d3: The generated API reference now documents every non-component export of every entry point (root, `kit`, `vite`, `astro`, `actions`, `seo`, `forms`, `tokens`, `table`, `charts`): `setLocale`, `registerLocale`, `caErrorPlugin`, `createErrorHandler`, `nativeFeel`, `usePageTitle`, `primeKeyboard`, the stores, the `seo` builders and the types, each with its signature and a JSDoc summary. `components.json` gains an `exports` array, `API.md` gains a "Non-component exports" section, the `ca-ui-mcp` server gains a `get_export` tool, and components of `kit` such as `RouteAnnouncer` now appear in the component list. The summaries were added as JSDoc, so they also show in editor tooltips.
- 648a1e6: New `.ca-sr-only` utility (visually hidden, still in the accessibility tree) and `.ca-sr-only--focusable` (shown again while it or a descendant has focus, for skip links). Apps can now add a table `<caption>` or an AT-only label without custom CSS. Both live in `styles/utilities.css` (`ca.utilities` layer), so `core.css` and `global.css` carry them. Documented in `getting-started/accessibility` and `docs/css-api.md`.
  
  The kit now uses it instead of eight copies of the clip pattern (`Dialog`, `Select`, `DocsSearch`, `Lightbox`, the date pickers, and the page titles of `PageShell`, `AppForm`, `AppList` and `AppSettings`; the `Table` cards-mode header row shares the same rule). Visual output is unchanged.
  
  Migration: four internal class names are gone because they only existed to hide text. If your CSS targeted `.ca-dialog__sr-only`, `.ca-sel__sr`, `.ca-docs-search__sr` or `.ca-lightbox__sr`, target `.ca-sr-only` instead (these elements now carry that class). The page `<h1>` hidden inside `AppShellLayout` below 900px now also carries `.ca-sr-only--shell`.
  
  Bundle budget: `styles/core.css` +173 B gzip and `styles/global.css` +206 B gzip (limits raised to the measured 9812 / 12800 B). The cost is the new public utility (the box, the focusable variant and two scoped copies that a class cannot express as one rule: the shell page title under a media query, the Table cards header under a container query); the eight component-level copies it replaces were already part of component CSS, not these entry files.
- 19386b1: Add the `@codeatlasdev/ui/testing` subpath: `expectNoA11yViolations`, `checkA11y`, `formatViolations`, `settled` and `A11Y_EXCEPTIONS`. It is the library's own axe helper (animations settled, `region` disabled for isolated components), framework-agnostic (takes an `Element` or `Document`), with `axe-core` as an optional peer dependency.
- a88b8a9: `EmptyState` and `GlassCard` accept `headingLevel` (`2 | 3 | 4 | 5 | 6`) to render their title as that heading without changing how it looks. `EmptyState` inside `PageShell` now defaults to `<h2>` (it was always `<h5>`, which made axe report `heading-order` under the page `<h1>`); outside a `PageShell` it stays `<h5>`. `GlassCard` renders `title` as a `<p>` unless `headingLevel` is set, so existing outlines are unchanged. New exported type `HeadingLevel`.
- 5f7d842: New `KpiGrid`: a responsive row of `KpiCard`s that never leaves an empty cell. `Grid cols="repeat(auto-fill, minmax(160px, 1fr))"` ignores how many cards it holds, so 3 cards on a 390px phone became 2 + 1 with a hole. `KpiGrid` counts its children in CSS (`:has()` quantity queries, no JavaScript, SSR-safe) and only uses column counts that divide that number: 3 cards are 3 across or one column, 4 are 4, then 2 x 2, then one column, 6 are 6, 3 + 3, 2 + 2 + 2. It follows its own width (container query), so it also works inside a sidebar layout. Above 12 children it falls back to `auto-fill`. Props: `gap`, `class`. New classes: `ca-kpi-grid`, `ca-kpi-grid__grid`.
  
  The docs, templates, demos and agent skill now use `KpiGrid` for KPI rows instead of the `Grid` auto-fill recipe.
- 4db46ab: Three patterns for result views, from the DX feedback in #48. `LiveList` shows rows that stream in (SSE, WebSocket, bulk jobs): a named `role="log"` with batched polite announcements instead of one per row, determinate or indeterminate progress, and auto-scroll that follows the newest row only while the user is at the bottom, pauses when they scroll up (with a "N new" jump button) and never moves focus. `ExternalLink` is a link to another site with `target="_blank"`, `rel="noopener noreferrer"`, a decorative icon and a localised "(opens in a new tab)" for screen readers (`externalLink.newTab` in the i18n catalog), made for table cells. `ExportMenu` is an Export button with a CSV / JSON `DropdownMenu`; the helpers `toCsv`, `toJson`, `downloadFile` and the `ExportColumn` type are exported too (RFC 4180, UTF-8 BOM in the downloaded CSV, spreadsheet formulas neutralised). New i18n keys: `externalLink`, `exportMenu`, `liveList` (en, pt-BR).
- 11809ff: `MoneyInput` accepts `currency` (ISO 4217; decimals come from `Intl`, so `JPY` has none and `BHD` has three) and `locale` (BCP 47). `value` is now the currency's minor unit rather than always cents. Existing BRL usage is unchanged: with neither prop set the field still renders `R$ 1.234,56`. With `currency` set and no `locale`, the locale follows the active i18n locale (`I18nProvider` / `setLocale`). `centsToDisplay` and `parseInputToCents` take an optional `{ currency, locale }` (defaults `BRL` / `pt-BR`), `parseInputToCents` reads the locale's decimal separator, and `currencyDecimals(currency)` and the `MoneyOptions` type are exported from `@codeatlasdev/ui/forms`.

### Patch Changes

- 5871641: AppShellLayout: the panel/main offset now uses the Svelte 5 `Spring` class and lands on the exact target (252px, not 251.984px). The extra CSS `margin-left` transition that lagged the spring is gone, and `prefers-reduced-motion` skips the animation and jumps straight to the target.
- ef7b0fa: CommandPalette: keyboard selection no longer gets stolen by the pointer. A row appearing under a stationary pointer (list renders, dialog animates in) fired `mouseenter` and moved the highlight; hover now follows real `mousemove`. ArrowDown on an empty list no longer stores `-1`.
- ee47b59: DocsSearch: keyboard selection no longer gets stolen by the pointer or reset by a lazy index. A row appearing under a stationary pointer (results render, dialog animates in) fired `mouseenter` and moved the highlight; hover now follows real `mousemove`. A lazy `index()` resolving while the dialog is open re-ran the open effect and wiped the typed query. ArrowDown on an empty list no longer stores `-1`.
- 7f5d8f7: `init` now writes the full SvelteKit setup: `caErrorPlugin({ scaffold: true })` next to `caThemePlugin(theme)` in `vite.config.ts`, and `handleError = createErrorHandler()` next to the theme `handle` in `src/hooks.server.ts` (both patched into existing files with `--write`, each only when missing; your own `handleError` is never replaced). The installation guide shows one complete SvelteKit setup, the exact files `init` writes, and states that plugin order in `plugins` does not matter.
- ea072c2: DropdownMenu, DataTable column toggle (and any `FloatingLayer` consumer): closing before the frame-delayed focus move ran no longer lets that move steal focus back from the trigger. `FloatingLayer`'s `onMounted` may now return a cleanup that runs on close/unmount.
- ba4c458: `PageShell` actions below 900px: a lone icon-only control (`IconButton`, `ThemeToggle`) no longer stretches to the full row with its icon centred. Icon-only children (`.ca-icon-btn`, `.ca-rail-btn`) keep their natural size and sit at the end of the row; labeled buttons still share the row full-width as before.