Skip to content

v0.1.8

Latest

Choose a tag to compare

@cixzhang cixzhang released this 23 Jul 00:25
c5fa19b

@astryxdesign/core

Breaking Changes

  • Avatar and AvatarGroup adopt Icon's abbreviated size scale — size now takes xsm/sm/md/lg/xl instead of tiny/xsmall/small/medium/large. Pixel values are unchanged (20/24/36/48/128px) and the default is now md (still 36px, formerly small). Avatar's tiers stay larger than Icon's because avatars align with media rather than glyphs. Run astryx upgrade to migrate call sites. (#2672)

New Features

  • Collapsible: the content area now anchors body typography (font family, size, weight, line-height) instead of inheriting from its surroundings, and exposes a stable astryx-collapsible-content theme target so revealed text can be themed externally.
  • Collapsible: add an isDisabled prop to disable a single item. A disabled item's trigger can't be toggled and is dimmed; following the system-wide disabled convention it uses aria-disabled (not the native disabled attribute) and drops out of the tab order, staying perceivable to assistive tech. Disabling doesn't collapse an already-open item. Works standalone and inside CollapsibleGroup.
  • @astryxdesign/core's docs.mjs now redirects to the CLI so agents converge on a single documentation entry point (astryx docs / astryx init) instead of a large standalone script. (#4207)
  • DropdownMenu selectable items: add DropdownMenuCheckboxItem (independent toggle, role="menuitemcheckbox") and DropdownMenuRadioGroup + DropdownMenuRadioItem (single-select, role="menuitemradio"). The control size derives from the menu's item size and swaps to the row's inline-end on touch. They also work inside ContextMenu (re-exported as ContextMenuCheckboxItem / ContextMenuRadioGroup / ContextMenuRadioItem). Both menus' keyboard/typeahead/activation now recognize the selectable roles, and the menu context (DropdownMenuContext, useDropdownMenuContext, DropdownMenuSize) is exported for building custom menu items. See #3829.
  • Icon: add an optional label prop for the accessible name. Setting it makes a standalone icon meaningful (role="img" + aria-label, no aria-hidden), collapsing the old three-attribute dance into one prop; omitting it (or passing '') keeps the decorative default (aria-hidden).
  • "Foolproof init": both @astryxdesign/core and @astryxdesign/cli now print a postinstall nudge pointing you to npx @astryxdesign/cli init, astryx commands nudge you to finish setup until init has run, and astryx init runs non-interactively (no TTY required) so it works in CI and agent environments. (#4147, #4153, #4154, #4155)
  • Outline: keyboard navigation, navigate callbacks, and scroll-scoping props (#2527)
    Layers the public API deferred out of #2746 onto the scroll-spy engine and click-lock that already shipped. No visual change.
  • Table: add a tree-data plugin — useTableTreeState and useTableTreeData — for rendering and managing hierarchical (parent/child) rows, expansion state, and flattening. Exported from @astryxdesign/core/Table. (#3789)

Fixes

  • AvatarGroupOverflow now grows into a pill for long +N counts so the number never clips.
    The indicator was a fixed-size circle, so wide counts (e.g. +4912) overflowed and crowded the edges. It now uses a minimum width equal to the avatar size plus horizontal padding: short counts (+5) stay a perfect circle, while longer counts grow horizontally into a stadium/pill and remain legible. No new public props.
  • Carousel now scrolls horizontally when you hold Shift and scroll the mouse wheel. Trackpad users already got horizontal scroll for free; this brings standard mouse (vertical-only wheel) users to parity using the established Shift + wheel convention. Native trackpad horizontal scrolling and the prev/next buttons are unchanged.
  • Citation: a non-interactive citation (no source.url) now keeps the default cursor instead of showing a pointer, so only linked citations look clickable. The pointer cursor is applied alongside the existing hover treatment for both the label and number variants (#4134).
  • Stop suggesting bare npx astryx before the CLI is installed — it resolves to an unrelated package on the npm registry.
    The CLI now emits an install-aware invocation everywhere it prints a command:
  • Icon: size variants (xsm/sm/md/lg) now use rem instead of hardcoded px, so icons scale in step with text when the document/root font-size changes — matching the rest of the design system's rem-based type scale. Fixes #4092.
  • Guard useTableRowExpansionState tree walks against cyclic data (#3971)
    The depthMap, flattened data, and allExpandableKeys walks now track the ancestor keys on the current path and skip edges that point back at an ancestor, so self-referential or cyclic row data terminates instead of overflowing the stack.
  • Route the Table sortable plugin's header-button aria-labels ("Sort by …", "… sorted …", "… priority … of …") through useTranslator() with new @astryx.table.sort.sortBy / sortedBy / sortedByWithPriority / direction.* catalog keys, so they localize like the sort menu labels already do (#3618, tracker #3636). The direction word resolves through its own key rather than interpolating the raw enum value. English output is unchanged.
  • Table: the tree row expander's aria-label is now localized through useTranslator() instead of a hardcoded English string, so expand/collapse controls announce in the app's language. (#4149)
  • TabList hasDivider reserves a gap so the hover pill and adjacent buttons no longer touch the underline
    A divided TabList now reserves 4px between the tabs and the divider rail. The hover highlight sits clear of the underline, and a same-size Button placed alongside the tabs aligns to the tab baseline instead of butting the rail — so a md tab strip pairs with a md button. The selected indicator still rests on the rail. Non-divided tab lists are unchanged. TabList inside a Toolbar with dividers={['bottom']} gets the same alignment via the toolbar's own spacing.
  • TreeList: focusing a parent row no longer leaks the focus-visible outline onto its descendant rows — each row's ring now resolves from its own nearest treeitem instead of matching any focused ancestor (#4130)

Documentation

  • DropdownMenu and DropdownMenuItem: seed playground defaults so the docsite properties-tab preview renders real content instead of an empty trigger.

Other Changes

  • Installed / global / dev runs suggest <pm> astryx <cmd> (e.g. pnpm exec astryx …), unchanged.
  • One-off runs (launched via npx/pnpm dlx/yarn dlx/bunx) suggest the scoped package <dlx> @astryxdesign/cli <cmd>, which always resolves to us.
  • Improved translator context in the shipped English catalog (packages/core/locales/en.json) descriptions. Sharpened ~172 entries — added screen-reader-only clarifications, ICU-composition examples, polysemy warnings, and set-pairing notes — so translators working in Crowdin get better context. No changes to defaultMessage values, keys, or runtime API.
  • Keyboard navigation — the outline is now a single tab stop (roving tabindex via useListFocus), seated on the active heading per WAI-ARIA, so tabbing into a table of contents while reading section 7 lands on section 7 rather than sending the reader back to section 1. Arrow keys move between headings, Home/End jump to the ends, and Enter/Space activate. A 40-heading table of contents costs one Tab press instead of 40, and Tab still leaves the outline in one press.
  • onNavigateStart(id) / onNavigateEnd(id) — fire around the smooth scroll started by a click or keyboard activation, so an app can drive an arrival effect. onNavigateEnd resolves on scrollend where supported and on a settle timeout where it is not (Safari), so it also fires correctly when reduced motion collapses the scroll into an instant jump. It fires exactly once for every onNavigateStart — including when the user interrupts the scroll — so a "navigating" state can never leak.
  • offset — the height of a fixed header overlaying the top of the scroll root. It shifts both the activation line and the scroll landing by the same amount, so a heading activates exactly where navigating to it puts it: below the header, not hidden underneath it. It composes with each heading's own scroll-margin-top (the header, then the breathing room below it) rather than replacing it — leave offset at 0 when nothing overlays the content and let scroll-margin-top do the work, since the browser already honors it.
  • scrollContainerRef — scope scroll tracking to a specific container instead of auto-detecting the nearest scrollable ancestor. Fixes the table of contents whose highlight never moves inside a split pane, modal, or dashboard panel. The default (viewport) path is unchanged.
  • hasScrollOnClick (default true) — set to false to own the scrolling yourself; the outline still updates the active item, the hash, and the navigate callbacks.

@astryxdesign/cli

Breaking Changes

  • Avatar and AvatarGroup adopt Icon's abbreviated size scale — size now takes xsm/sm/md/lg/xl instead of tiny/xsmall/small/medium/large. Pixel values are unchanged (20/24/36/48/128px) and the default is now md (still 36px, formerly small). Avatar's tiers stay larger than Icon's because avatars align with media rather than glyphs. Run astryx upgrade to migrate call sites. (#2672)

New Features

  • astryx init --features agents now defaults to creating root AGENTS.md — the tool-agnostic standard that Codex/Copilot, Cursor, and most agents read — instead of the Claude-specific .claude/CLAUDE.md. Claude output is now opt-in via --agent claude (→ .claude/CLAUDE.md), and --agent all still writes both. Projects with existing agent-doc files are unaffected: init still discovers and updates every file already present, so this only changes the from-scratch default. (#4216)
  • "Foolproof init": both @astryxdesign/core and @astryxdesign/cli now print a postinstall nudge pointing you to npx @astryxdesign/cli init, astryx commands nudge you to finish setup until init has run, and astryx init runs non-interactively (no TTY required) so it works in CI and agent environments. (#4147, #4153, #4154, #4155)

Fixes

  • Stop suggesting bare npx astryx before the CLI is installed — it resolves to an unrelated package on the npm registry.
    The CLI now emits an install-aware invocation everywhere it prints a command:
  • Extend the v0.1.0 upgrade codemods to cover test files that mock @xds/core modules, which were previously left half-migrated and broke after upgrade:
  • astryx upgrade now keeps the managed agent-docs block (<!-- ASTRYX:START --> … <!-- ASTRYX:END -->) in sync with the installed version on every path — including the up-to-date and no-codemods short-circuits that previously returned before any refresh, leaving AI agents reading a stale component index and superseded rules. The block documents the installed library, so it's now refreshed up front (independent of codemods) and reported in the --json receipt as agentDocs. One detection pass covers three cases: a stale block is rewritten (--apply) or reported as a pending change (dry-run, which no longer writes); a project with core installed but no managed block is nudged to run astryx init --features agents; an already-current block stays silent. (#4168, #4169)

Documentation

  • Add a cli-integrations CLI docs topic (astryx docs cli-integrations) so the integration-authoring guide (originally written by @ejhammond) is discoverable through the CLI and docsite instead of an unreferenced markdown file. Rewrite the CLI README's Configuration section to match the current strict config schema (integrations, issuesUrl, hooks.postCodemod, experimental.xle) and reframe the Integrations section around the two-file API.

Other Changes

  • Installed / global / dev runs suggest <pm> astryx <cmd> (e.g. pnpm exec astryx …), unchanged.
  • One-off runs (launched via npx/pnpm dlx/yarn dlx/bunx) suggest the scoped package <dlx> @astryxdesign/cli <cmd>, which always resolves to us.
  • migrate-xds-module-specifiers: rewrite the mocked-module path in vi.mock/vi.doMock/jest.mock/jest.doMock (and bare mock) calls, plus import(...) specifiers used in TS type positions (typeof import('@xds/core/Text')), so the mock still intercepts the renamed @astryxdesign/* import.
  • drop-xds-prefix-imports: un-prefix partial-mock override keys inside an @xds/core mock factory (e.g. useXDSTruncationuseTruncation) so the override matches the renamed export instead of silently overriding nothing. Scoped to recognized @xds/core mock factories only; unrelated object keys are untouched.

Contributors

Thanks to everyone who contributed to this release:

Full Changelog: v0.1.7...v0.1.8