Skip to content

@codeatlasdev/ui@4.2.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 21:18
· 193 commits to main since this release

Minor Changes

  • b65d56d: AI feedback loop. The ca-ui-mcp server has a new report_issue tool: an agent that hits a library problem (bug, missing prop or component, migration gap, wrong docs) gets a sanitized issue draft (paths, foreign URLs, emails, IPs, tokens, env assignments and foreign package scopes are redacted, and the redactions are listed) with a prefilled link to the new "AI report" issue form and a gh issue create command. It never posts. bunx @codeatlasdev/ui workarounds lists the // ca-ui-workaround(#<n>): <why> markers an agent left in your code and which issues are already closed (read-only, offline-safe, exit 0).
  • 81910d1: Avatar renders the photo as a real <img> (no detached Image() probe, so no double download) and passes loading, referrerpolicy and crossorigin through, so loading="lazy" keeps a 200-row list from firing 200 requests and referrerpolicy="no-referrer" works with CDNs that reject a cross-origin Referer. fallback now also takes a snippet (an icon for groups, channels and bots), and onerror fires when the image fails so you can refetch a signed URL. The fallback is always rendered beneath the image, so the box never changes size. The data-status attribute on .ca-avatar is gone.
  • 80c0336: Card has a padding prop ('none' | 'sm' | 'md' | 'lg', any CSS length, or a number of pixels) so a one-off density no longer needs an inner wrapper; flush stays as the alias of 'none'. The docs now say that Card's content is already padded, and in development a [ca-ui] warning (card-double-padding) fires once when the first child adds its own padding on top of the card's (the 20px + 20px = 40px "oversized card").
  • cd655bb: Chat primitives: MessageBubble (direction, grouped tails, sender and avatar slot, quote, reactions, delivery ticks), ConversationItem (inbox row with unread, pinned, muted, typing, active), AudioPlayer (lazy src, waveform from peaks, slider semantics, playback rate), MediaGrid (image, video and document tiles opening a Lightbox gallery) and VirtualList (windowing plus load-older at the top that keeps the scroll position). New chat, audioPlayer, mediaGrid and virtualList messages in en and pt-BR.
  • 80c0336: CopyButton takes aria-label for the icon-only form (label=""), so each row of a list or table can announce its own name ("Copy client_id of Acme") instead of the same localized "Copy". The default stays the i18n copyButton.label. The label is ignored when label is visible, so the accessible name keeps containing the visible text. Remaining attributes (data-*, id, aria-describedby, …) are now forwarded to the underlying button.
  • 6e08799: Every numbered demo now has a reviewed <Variant>.meta.json sidecar (summary, use, spec, tags, shape), so get_demo, search_demos and /api/v1/en/{e,p}/NNN.txt return what the demo shows, when to use it and a Spec list of its literal values (props, snippets, state, counts). The catalog check (manifest --check, run by every build) now fails on a demo without a sidecar, a sidecar without a demo, an unknown key, a bad shape, or a spec line that quotes a token that is not in the demo source. New codeatlas-ui pick [ids...] opens the gallery, listens on 127.0.0.1 with a random per-run token and prints the ids you send with "Send to AI" (#005 #012).
  • d99cead: codeatlas-ui init scaffolds SEO and PWA on SvelteKit (#205): prerendered manifest.webmanifest, robots.txt and sitemap.xml routes built with the seo helpers, a service worker (src/service-worker/index.ts on $app/service-worker, $app/manifest and $app/env for Kit 3; src/service-worker.ts on $service-worker for Kit 2) with a prerendered /offline page, and a default <Seo> with canonical and manifest link in the root layout. Existing files are never overwritten; after creating them init reminds the app to set paths.origin (otherwise Kit's prerender placeholder origin reaches the sitemap and canonical URLs), add the icons and exclude src/service-worker from tsconfig.json on Kit 3.
  • d99cead: New InstallPrompt (#208): a dismissible banner that offers to install the app. On Chromium it keeps beforeinstallprompt (no browser mini-infobar) and shows an Install button that opens the native dialog and reports the choice with onchoice; on iOS Safari and iPadOS, which have no install API, it shows the Share, Add to Home Screen steps. It renders nothing when the app already runs standalone, and stays hidden for dismissDays (default 14) after the user closes it. Strings are in the installPrompt i18n group (en, pt-BR); the root: Button only size budget rises by 240 B gzip because both catalogs ship with every root import.
  • 81910d1: Lightbox opens videos and galleries. items ({ type?: 'image' | 'video', src, alt?, caption?, meta?, poster?, download? }, exported as LightboxItem) plus a bindable index add previous/next buttons, ArrowLeft/ArrowRight and swipe (no wrap; the end buttons are aria-disabled so focus stays put), a counter, caption and sender/time line, video with controls (paused when you move on), and a Download button (ondownload or a plain <a download>). src/alt still work as a single-item shortcut. New lightbox.previous, next, download and counter labels in en and pt-BR; the close button moved into a .ca-lightbox__tools bar.
  • 3180023: Leading icon slot for DropdownMenuItem and TabsTrigger, and a documented pattern for brand logos (#194). icon is a snippet rendered in a fixed 14px box with the standard gap and aria-hidden (the label stays the accessible name), so icon size and alignment no longer drift between menus. brandIcon marks the icon as a fixed-color brand mark: no highlighted, disabled, active or destructive color reaches it (trademark guidelines forbid recoloring). New SchemeAsset takes light and dark snippets and shows the one for the kit's color scheme (.dark on <html> or a data-theme-scope island) with CSS only, so it is right in SSR and on first paint and apps no longer read the theme store for logo variants. New classes: .ca-dropdown-item__icon, .ca-tabs-trigger__icon, .ca-scheme-asset, .ca-scheme-asset__light, .ca-scheme-asset__dark.
  • 7a112eb: Navigation: LoadingBoundary wraps <svelte:boundary pending> with a 200 ms delay and 500 ms minimum so a loading UI never flashes (default placeholder is Skeleton rows, aria-busy, named region). @codeatlasdev/ui/kit gains NavigationProgress (top bar driven by navigating from $app/state) and the pendingLink() attachment that sets data-pending on the link being navigated to. A test now proves AppShell stays mounted across 10 client-side navigations.
  • df50d86: New RecordList, RecordRow and RecordCell: records as dense rows (identity, a few columns, a row menu) that re-flow to a compact two-line row on a phone. The list owns the flush container, the separators, one columns template shared by the header and every row, the re-flow (a container query on the list's own width, 36rem), the 44px actions cell and an aria-hidden header whose labels become per-cell dt when stacked. It replaces the hand-rolled flush Card + grid + :global row CSS, and is much shorter on a phone than Table responsive="cards".
  • d99cead: <Seo> completes the social and language tags (#207): og.defaultImage is the site-wide card used when a page has no og.image (also feeds twitter:image and the summary_large_image card), twitter:title and twitter:description mirror the page title and description, and the new lang prop sets og:locale and keeps <html lang> in sync on the client.
  • 81910d1: skeleton prop on Avatar, KpiCard, TextField, Table, Card and GlassCard: the component keeps its real DOM, so the placeholder has exactly the loaded size (no layout shift). Content is laid out but hidden, the host paints the same shimmer as <Skeleton>, and it is announced with aria-busy="true"; a skeleton TextField is disabled and an Avatar makes no image request. Reduced motion stops the sweep and forced colors draw an outline. New global [data-skeleton] rule and ca-shimmer keyframes in utilities.css.
  • f889334: Every backdrop blur now comes from one place. Components no longer declare backdrop-filter: they set data-ca-blur="<role>" (or are a .ca-surface) and styles/surface.css paints it from the tokens <html data-style> rewrites, so one attribute turns every blur off or down together. The look is unchanged (guarded by a computed-style test over 9 styles, light and dark). FloatingLayer gains a blur prop (overlay or tooltip). lint:tokens rejects backdrop-filter outside surface.css and materials.css. The MCP server gains list_surfaces, generated from the [data-style] selectors in materials.css, and dist/surfaces.json ships with the package.
  • 3180023: TabsList handles its own overflow (#190). It keeps the width of its tabs inside Tabs (no more full-column pill on desktop), and when the tabs do not fit it scrolls sideways on its own with the scrollbar hidden and scroll snapping, instead of wrapping or widening the page on a phone. The selected tab is scrolled into view on mount and when it changes (only the strip scrolls, never the page). New optional fade prop masks the edge that still hides tabs, like the AppSettings nav. The wrapper div with overflow-x: auto and the :global(.ca-tabs-list) { width: max-content } workaround can be deleted.

Patch Changes

  • 526fee2: A menu, Select list, popover or tooltip that is already open when a Dialog, Sheet or Drawer opens (a shortcut or an async action opening the modal over it) now moves into that modal and stays clickable and above it. Before, it stayed outside the modal, so it went inert and could not be used. When a modal closes before the popovers hosted in it, they are handed to the next modal or put back where they were declared instead of being removed with it. The layer stack and the stacking contract are covered by new tests and documented on the Dialog page (#225).
  • 3afd417: Overlays return focus to the control that opened them on iPhone/iPad and Safari too. WebKit does not focus a tapped button (it focuses a focusable ancestor such as <main tabindex="-1">, or nothing), so focus used to land there on close and VoiceOver users lost their place. CommandPalette: Mod+K focuses the search field on touch devices with a keyboard (covered by a test now).
  • c76c837: New guide getting-started/migrate-react, readable offline through the MCP get_guide("migrate-react") and on the docs site: decision flow (incremental or rewrite), React hook to Svelte 5 rune map with the effect pitfalls, MUI / shadcn-Radix / Chakra to @codeatlasdev/ui component maps, layout templates, theme mapping, TanStack Table to @codeatlasdev/ui/table, and how to report a gap (report_issue kind migration-gap plus a ca-ui-workaround marker). A unit test fails when a component named in the maps stops being an export.
  • d99cead: The manifest generateBrand / caBrandPlugin write is installable: display: "standalone" (was "browser"), id and scope set to "/", and theme_color / background_color taken from the theme's default scheme instead of always the light one (#206). The icon hash now includes the default scheme, so switching it renames the files.
  • 81910d1: Skeleton's shimmer is a translated ::after band instead of an animated background-position, so it no longer repaints on every frame. Reduced motion still gets a static, dimmed placeholder.
  • 9c9df3b: @codeatlasdev/ui/vite is safe in the SSR graph: importing designStyle, mergeTheme or ThemeOptions from a theme.ts that hooks.server.ts shares no longer fails the SvelteKit server build with UNLOADABLE_DEPENDENCY on @resvg/resvg-js (#184). The native peers are loaded by name at run time and caBrandPlugin marks them ssr.external, so the ssr.external workaround is no longer needed. runBrand and brandUrls are now exported from @codeatlasdev/ui/vite, as the 4.0.0 changelog announced (#185).

Install

bun add @codeatlasdev/ui@4.2.0

Special thanks

To our main supporters and special contributors, Fábio Henrique Araújo (@FabioHAraujo) and Richardson Douglas (@Richards0nd). 💛