Skip to content

@codeatlasdev/ui@2.3.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 18:50
· 280 commits to main since this release
5bb1d1e

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 KpiCards 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.