Skip to content

@codeatlasdev/ui@4.4.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 14:03
· 161 commits to main since this release
de861dd

Minor Changes

  • 1c6653e: NavItem in the AppShell panel gets color (a decorative dot), leading (a snippet that replaces the icon), count (a neutral total, announced as a bare number instead of "N unread", 1.2k above 999) and actions (a snippet of DropdownMenuItems behind a "…" button named "Actions for ") (#275). NavSection.onReorder and NavModule.onReorder make the rows reorderable with the useDnd primitive: a grip per row, mouse, touch press-and-hold and keyboard, with announcements; the shell reports { id, from, to } (new NavReorderEvent type) and never reorders items itself. PanelNavItem now renders a row that contains the <a class="ca-nav-item__link"> (a link cannot hold the actions button or the grip), so .ca-nav-item is the row, not the anchor. New messages appShell.itemActions and appShell.moveItem.

  • 1c6653e: AppShellLayout takes panelWidth (px, held between 160 and 480, default 200) and resizablePanel (#292). The content offset and the open and close animation follow the width, so a panel for long labels no longer misaligns the page. resizablePanel adds a keyboard-operable drag handle on the panel's trailing edge (Arrow keys 8px, Shift 32px, Home and End for the bounds); with persistPanel the chosen width is stored in ca-shell and restored by the inline script before the first paint. New appShell.resizePanel message and .ca-panel__resize class.

  • ca80cfd: Combobox: multiple turns it into a searchable multi-select (value is string[], aria-multiselectable listbox, list stays open, removable chips, Backspace on an empty query removes the last chip) and creatable works in both modes. CommandPalette: search(query, signal) adds debounced (searchDebounce), abortable server-side results with loading, empty and failed states announced through announce(), plus onSelect and the exported CommandResult type.

  • 49116d1: DataTable gains row groups, column resize, row reorder and safer interactive cells (#283). groupBy renders one <tbody> per key with a collapsible header (aria-expanded, groupLabel to customize). meta.resizable on a column adds a window-splitter handle (mouse, touch, keyboard arrows, Shift, Home, End, Enter) driven by size, minSize and maxSize; the new DataTableColumnResize is exported for hand-built headers. onReorder adds a drag grip per row on top of the new useDnd primitive, moves rows between groups and reports { id, from, to } (DataTableReorderEvent); rowId gives rows stable ids and pageSize sets the page size in simple mode. A click on a link, button, input or other control inside a cell no longer fires onRowClick (add data-no-row-click to opt other elements out). The new labels (Reorder, Move, Resize) follow the active locale (en, pt-BR). Needs the drag and drop primitive from #284.

  • d138bd8: New drag and drop primitive, useDnd(), applyMove and <DndLayer>, for sortable lists, moves between lists and drop zones (#284). It works with mouse and pen (4px threshold), touch (press and hold, so the page still scrolls) and keyboard (Space lifts, arrows move, Home/End jump, Enter drops, Escape cancels), speaks every step through announce() (English and Portuguese built in, useDnd({ messages }) for others), auto-scrolls near the edges of a scrolling container and drops its animations under prefers-reduced-motion. The engine measures the boxes once per drag and only moves a clone, a drop line and data-dnd-* attributes, so the list does not re-render until onDrop. <DndLayer {dnd} /> renders the keyboard instructions and the forced-colors aware styles (.ca-dnd-overlay, .ca-dnd-indicator), so apps that never drag add no bytes to core.css or to the i18n catalog.

  • 946d69d: Drawer can be named without its default title: pass aria-label, aria-labelledby (your own header) or hideTitle, and id, data-* and other attributes now reach the <dialog> (#285). AlertDialog gains confirmProps and cancelProps (attributes for the two buttons) and cancelVariant (#287), plus a children body, a description that accepts a snippet and confirmDisabled for type-to-confirm (#278).

  • e983caa: DropdownMenu is controllable and can open at a point. bind:open and onOpenChange read and set the open state; anchor={{ x, y }} opens the menu at a viewport point (a right-click menu, no trigger needed) and changing it while open moves the menu instead of toggling it. A menu opened from code starts on its first item and returns focus to the element that had it. On the built-in trigger Shift+F10 and the ContextMenu key open the menu like ArrowDown.

  • e983caa: DropdownMenu gains selection items. DropdownMenuCheckboxItem (role="menuitemcheckbox", bind:checked, onCheckedChange) and DropdownMenuRadioGroup + DropdownMenuRadioItem (role="menuitemradio", bind:value, onValueChange) render aria-checked and a check indicator, stay open after a pick (closeOnSelect closes), and join arrow, Home, End and typeahead navigation (the menu now also recognizes menuitemradio).

  • e983caa: DropdownMenu gains submenus. DropdownMenuSub takes a trigger snippet holding a DropdownMenuSubTrigger item (aria-haspopup="menu", aria-expanded, chevron) and the submenu items as children; they nest to any depth. ArrowRight, Enter or Space opens the submenu on its first item, ArrowLeft or Escape closes only that level, hovering the trigger opens it after a short intent delay and the pointer can cross into it. Selecting an item closes every level. A popover layer that is closing no longer owns Escape or outside presses, so a closing submenu hands them to its parent.

  • ff460ad: Form controls forward native attributes and expose their element, with one vocabulary (ref, hideLabel, rest props on the native element):

    • Checkbox, TextField, TextArea and FileUpload spread every other attribute and handler (data-*, maxlength, inputmode, onclick, onkeydown, name, capture...) on the native <input>/<textarea>, and take a bindable ref with that element. Checkbox onchange now receives the native event as a second argument, and its forwarded onclick makes Shift range selection possible. TextField/TextArea gain onfocus and hideLabel (label kept for screen readers with .ca-sr-only; aria-label also works without a label).
    • Select accepts aria-label and aria-labelledby for a compact select without a visible label. The trigger is named by that text followed by the current value (visible text stays in the name); without either, the placeholder names it as before.
    • FileUpload gains ref, an open() instance method for a button outside the dropzone, and list={false}: a plain picker whose onchange receives only the files just picked, with no built-in list and nothing kept in files (the native input is cleared, so the same file can be picked again).
  • 8c24c31: Theme option motion: { enter: "none" } (token --ca-enter-scale: 0) turns off entrance and exit animations only: Dialog, AlertDialog, Drawer, Sheet, Lightbox, CommandPalette, DocsSearch, date pickers, DropdownMenu, Popover, Tooltip and Toast appear and leave in place, while hover and focus color transitions keep --ca-duration-*. New derived tokens --ca-enter-fast, --ca-enter-base and --ca-enter-slow; MotionStage demos render their final state when the theme turns entrances off, as under prefers-reduced-motion (#268).

  • 16f89dd: Popover is controllable. bind:open and onOpenChange read and set the open state, and the children snippet receives close, which closes the popover and returns focus to the trigger, so a choice made inside it (a Calendar day, an option) can dismiss it. Existing popovers are unchanged.

  • 8c24c31: New --ca-radius-round token (999px × --ca-radius-scale): "fully rounded at the current scale". SwatchGroup swatches, the AppShell active pips (.ca-nav-item__pip, .ca-rail__pip) and the new-item dot, and .ca-nav-item__badge use it, so a theme with radius: 0 squares them with no app CSS (#267). --ca-radius-chip now aliases it. --ca-radius-pill stays a fixed 999px for functional shapes (Switch, Slider, Progress, scrollbars) and for controlRadius: "pill".

  • 946d69d: Tabs gains variant="line" (bare text tabs with an underline on the active one, for page headers), and TabsList and TabsTrigger forward rest attributes: aria-label names the tablist, data-*, id and event handlers reach the trigger button (#286). A TabsTrigger now points aria-controls at its panel only while a TabsContent with the same value is mounted, so tabs used as view switchers no longer reference missing elements.

  • 2ab0d93: ToggleGroup gets required: pressing the active item no longer clears the selection (radio-like, onchange stays silent; type="multiple" keeps its last pressed item). An empty group still selects on the first press. Closes the gap with SegmentedControl for filters that must look like contiguous buttons.

Patch Changes

  • 05cfbfc: AppShellLayout: an item at path: "/" is active on / only, no longer on every page, and a module at basePath: "/" only gets the pages no other module claims. Module prefixes (basePath, pathPrefixes) match whole path segments and the longest one wins, whatever the module order (/settingsfoo no longer matches /settings).
  • 98d2ace: Astro: the theme now survives <ClientRouter /> (View Transitions) navigations. caUI registers an astro:before-swap handler that carries #ca-theme, #ca-runtime-tokens, the theme-color meta and the theme attributes onto the incoming document (#265). codeatlas-ui init on Astro also adds svelte() from @astrojs/svelte to integrations, and notes npx astro add svelte when the dependency is missing (#273).
  • 3ae1f41: Button with href now types the anchor's own attributes: download, rel, hreflang, ping, referrerpolicy and type (the linked resource's MIME type) are accepted instead of rejected, as ...rest was already spread on the <a>. The props are a union keyed on href: a link takes anchor attributes, a button takes button attributes (form, formaction, name, value...), and <Button download> without href is a type error. At run time a type passed with href reaches the <a>, and a caller rel is kept and merged with noopener noreferrer when target="_blank" (it used to be overwritten).
  • 5c9ac81: CommandPalette: new shortcut prop (default true). With two palettes on one page, every instance opened on Mod+K; set shortcut={false} on all but one, or when the app binds its own shortcut.
  • a61874b: Calendar, RangeCalendar, DatePicker and DateRangePicker: fast arrow-key sequences no longer lose keys. The roving focus now moves synchronously instead of after tick(), so the next key always starts from the day it lands on, with or without Svelte's experimental.async.
  • e983caa: DropdownMenuItem forwards its remaining attributes (data-*, id, aria-*, title, ...) to the menuitem element. data-testid and aria-keyshortcuts used to be dropped. role, tabindex and the selection handler stay owned by the item.
  • ff8686f: DropdownMenuItem and TabsTrigger icon slots now size any svg or img inside the 14px box, not only a direct child. A SchemeAsset logo (its variants sit in display: contents spans) used to collapse to 0×0 when the svg had no width/height, and an svg with a fixed width="24" overflowed the box; both now fill the box.
  • d01c039: LoadingBoundary counts minDuration from the moment the placeholder reaches the DOM instead of from the state change that schedules it, so a busy main thread no longer shortens the time the placeholder is visible.
  • 23276cf: Fix Escape going to the wrong layer. A Dialog, AlertDialog, Drawer, Sheet, Lightbox, CommandPalette or DocsSearch that is playing its exit animation no longer takes Escape or presses: they reach the layer below, so closing a confirm dialog and pressing Escape right after closes the Drawer under it (#288). A menu or popover that was open when a modal opened now ranks above that modal, so Escape closes the menu first and the dialog second instead of closing the dialog and leaving the menu open (#299). Exit animations of components that use createPresence (Dialog, Drawer, AlertDialog, menus, popovers) now keep the node mounted through the exit instead of removing it in the flush that closes it, and a menu hosted in a dialog is no longer left stranded after its exit.
  • 05cfbfc: Rail: the dock magnification scales the module icon (the glyph), not the whole button, so the hovered background no longer covers the active neighbour's background and pip. The effect follows --ca-motion-scale: it is off with motion: { scale: 0 } and under prefers-reduced-motion.
  • 05cfbfc: Native button, input, select and textarea inherit the page font (font: inherit in the new ca.reset layer, styles/reset.css) instead of the browser's UA font. The AppShell section header (.ca-section__trigger / .ca-section__label) and any control without its own font rule now render in --ca-font-sans. Component and app rules still win: the layer is the first one.
  • 8c24c31: Skeleton and the skeleton prop follow the theme surface style: under flat, solid and outlined no gradient band is drawn, the placeholder is a flat block that pulses its opacity (ca-skeleton-pulse, stopped under reduced motion). Glass, frosted, neumorphic, clay, chrome and tonal keep the shimmer sweep (#280).

Install

bun add @codeatlasdev/ui@4.4.0

Special thanks

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