Releases: facebook/astryx
Releases · facebook/astryx
Release list
v0.1.2
@astryxdesign/core
Breaking Changes
Text,Heading,Link, andTimestamprename thecolor="active"value tocolor="accent", now mapping to the dedicated--color-text-accenttoken (legible accent text ink) instead of--color-accent. Runastryx upgradeto migrate call sites automatically. (#2863)
New Features
- Button: add
isInterruptibleto keep the button clickable while aclickActionis pending — the spinner andaria-busystill show, but the button is not disabled or deduped, so a re-click interrupts the in-flight action. ToggleButton's async toggle now runs through this path, staying interruptible. - Add a prebuilt UMD bundle (
dist/astryx.umd.js, globalAstryx) plusunpkg/jsdelivrfields, so the library works directly from a CDN via a<script>tag with no bundler. React/ReactDOM stay as peer globals; the StyleX runtime is bundled in. - Add
useTableStickyColumns— pin a contiguous run ofTablecolumns to
the start and/or end edge with cumulative offsets and scroll-aware drop shadows.
Configure with{ startKeys, endKeys }; an empty config is a valid no-op.
Fixes
- AvatarGroupOverflow now forwards rest props (data-, aria-, event handlers, id, role, tabIndex) to the rendered element, matching the behavior of Avatar and AvatarGroup.
- Fix HoverCard SSR hydration mismatch when used inside an SSR Client Component (#3107). The floating layer now renders inline instead of portaling to
document.body, so server and client markup match. No API change. - Kbd: use the
--color-border-emphasizedtoken for its bottom border instead of--color-border(#2850) - useLayer now treats
anchor-nameas a comma-separated list, so multiple layers can anchor to the same element (e.g. two TopNavMegaMenus in one nav) without clobbering each other's anchor. Previously the second menu lost its anchor and rendered over the nav. - Fix mobile nav drawer not re-opening after it is closed (#3091)
The AppShell mobile drawer mountsMobileNavinside an<Activity>that
switches tomode="hidden"when the drawer closes. On close, React runs the
drawer effect's cleanup (with a staleisOpen) instead of re-running the
effect withisOpen=false, so the deferreddialog.close()never fired and
the native<dialog>was leftopenin the hidden subtree. The next open then
skippedshowModal()(the dialog was already open), so the drawer could be
opened and closed once but never re-opened. The effect cleanup now closes the
dialog if it is still open, keeping the native dialog state in sync so a
subsequent open cleanly callsshowModal()again. - Core components (
Banner,EmptyState,Markdown) no longer render a<p>by default — they render<div>(appearance unchanged). This avoids hydration mismatches when block content lands in a<p>.Markdownparagraphs userole="paragraph"; passcomponents={{paragraph: 'p'}}to opt back into<p>. Pagination'schangeActionis now interruptible — page changes run in a transition with optimistic page state, so rapid prev/next clicks advance through pages instead of being dropped.Button'sclickActionkeeps its single-fire guard.- make the
Sliderdefault track color visible on muted backgrounds
The background track painted with--color-background-muted— the same token
used for muted surface fills — so the track disappeared on muted backgrounds.
The track now uses the dedicated--color-trackchannel token, which is
designed to stay legible against body/muted surfaces. - Polish
useTableStickyColumnspinned-cell backgrounds so they match the
rest of the row: - Table: the header row no longer picks up the
hasHoverrow highlight — hover (and striped) styling now applies to body rows only. Adds an internalisHeaderRowflag on the row component so the header row in<thead>opts out (#2734) Timestampnow renders the current time (and small clock skew up to ~30s in the future) as "now" instead of "in a few seconds" (#3099).- ToggleButton onPressedChange receives the click event for preventDefault opt-out
onPressedChangenow receives the originating click event as a second
argument. Callingevent.preventDefault()skipspressedChangeAction, so a
consumer can handle the toggle entirely inonPressedChangewithout firing the
action — matching howSwitch'sonChangeandButton'sonClickalready
gate their action props. Existing(isPressed) => voidhandlers keep working;
the event is an added trailing argument. - Tokenizer/PowerSearch: align end content (clear button, resultCount) with the field's inline padding instead of hugging the border (~3px). It now uses spacing-2 (8px) to match the text/start-icon inset (#2849)
- Tooltip and HoverCard: add ARIA roles to the floating layers —
role="tooltip"on Tooltip (completing the ARIA tooltip pattern; the trigger already links viaaria-describedby) androle="dialog"on HoverCard. Plumbed via a new optionalroleon the layer render props. (#3240; Popover already exposesrole="dialog".)
Documentation
- Document Banner's
defaultIsExpandedprop, which controls whether the collapsible content area starts expanded but was missing from the docsite properties tab - Rename the ClickableCard and SelectableCard examples to follow the "Component — Variant" title convention (
Clickable Card — Nested Button,Selectable Card — Multi-select), and add playground defaults to both card docs so their docsite previews show realistic card content (#2877) - Declare playground scaffolds for the Chat sub-components so they preview at a realistic width (ChatComposer and ChatComposerDrawer wrap in a sized container, and the drawer seeds default content), and drop the redundant visible value label from the ChatComposerDrawer "With Progress" example while keeping the accessible label (#2877)
- Document two public props missing from the docsite properties tab: List's
start(ordered-list counter start) and CheckboxInput'sisReadOnly - Restore the Icon and Skeleton properties-tab previews on the docsite. Icon now seeds a default
icon(it was a required, non-generatable prop), and Skeleton renders with concrete preview dimensions instead of collapsing at100%(#2848, #2875) - Document Heading's
justifyprop, which was supported by the component but missing from the docsite properties tab (#2847) - OverflowList: seed example items via playground defaults so the docsite properties-tab preview renders a real list instead of an empty container (#2872)
- Document Section's
paddingBlockprop (block-axis padding override), which was supported by the component but missing from the docsite properties tab - Give the
Skeletonproperties-tab example explicit dimensions so it is visible
TheSkeletondoc had noplaygroundconfig, so the interactive
properties-tab preview fell back to the prop defaults ofwidth: '100%'/
height: '100%'. With no sized parent, the skeleton collapsed to a zero-size
(invisible) element. The doc now sets aplayground.defaultsof
width: 320/height: 80so the shimmer placeholder renders visibly. - Update stale
facebookexperimental/xdsdoc/JSDoc links to the currentfacebook/astryxnamespace in source comments (theme/syntax@seereferences). The old org 301-redirects, so these weren't broken — just stale — and this matches the canonical org used elsewhere - Document Table's
verticalAlignandtextOverflowprops, which were supported by the component but missing from the docsite properties tab - Document TabList's
layoutprop ('hug' | 'fill') for tab sizing, which was supported by the component but missing from the docsite properties tab - Document Text's
justifyprop, which was supported by the component but missing from the docsite properties tab (same omission previously fixed for Heading) (#2847-adjacent) - Restore the Timestamp properties-tab preview on the docsite.
valueis a required prop with no semantic default, so the preview rendered "Invalid time value"; it now seeds a valid ISO 8601 date (#2877) - Document ToggleButton's
isIconOnlyprop, which was a supported public prop but missing from the docsite properties tab - Make the Toolbar "Table Filter" example use real Selector controls for its Status and Priority filters instead of buttons styled to look like dropdowns, and add meaningful playground defaults plus richer slot options (buttons, icon buttons, tabs, segmented controls, selectors) to the Toolbar docs (#2877).
Other Changes
- Pinned cells paint an opaque base via the overridable
--table-sticky-backgroundvariable (defaults to--color-background-card),
fixing a grey mismatch in themes/modes wheresurface !== card(e.g. neutral
dark). Consumers on a different backdrop override the variable. - The row's overlay (striping and/or hover) is replayed on the pinned cell via
a background-image gradient.TableRowpublishes its current overlay color as
the inheritable--table-row-overlayvariable, so pinned columns mirror the
row exactly — striped when the table is striped, hover when enabled, nothing
otherwise (no phantom stripes) — transitioning in lockstep with the row. background-clip: padding-boxkeeps the row divider visible on pinned cells.- New
transformScrollWrapperhook (+ScrollWrapperRenderProps) lets plugins attach aref
to the horizontal scroll container and inject before/after chrome. transformHeaderCell/transformBodyCellnow receivecolumnIndexand the
full orderedcolumnslist (also surfaced on the render props), enabling
position-aware plugins such as sticky columns. Existing plugins are unaffected
— the new args and methods are additive and optional.
@astryxdesign/cli
Breaking Changes
Text,Heading,Link, andTimestamprename thecolor="active"value tocolor="accent", now mapping to the dedicated--color-text-accenttoken (legib...
v0.1.1
This release continues removing the xds naming from the public API, alongside component fixes and a new astryx build CLI workflow.
@astryxdesign/core
Breaking Changes
- Rename
xdsTokenDefaultsexport totokenDefaults(exported from@astryxdesign/core/theme). Update imports accordingly. Part of removing xds naming from the public API.
Fixes
ChatLayoutScrollButton: widen trailing inline padding when a label (e.g. "New messages") is shown so the text isn't cramped against the pill's rounded corner. The icon-only collapsed state is unchanged.DateInput: no longer crashes the page while typing an incomplete date. Typing a leading0or1could coerce the in-progress value into an invalid date (year0) and throw aRangeError. Partial input is now treated as incomplete instead of being parsed.Selector: remove doubled focus ring. The inner combobox button drew its own:focus-visibleoutline on top of the wrapper's:focus-withinring. The button now defers to the wrapper's focus ring, matchingTextInputandNumberInput.Layout:<Layout>…</Layout>no longer renders a blank page. Children now render as a shorthand for thecontentslot (<Layout>{main}</Layout>≡<Layout content={main} />); an explicitcontentprop still wins when both are provided.ToggleButton:pressedChangeActionnow runs inside an interruptible transition with optimistic pressed state (matchingSwitch), so the loading spinner appears and the action's lifecycle is respected. The optimistic state flips immediately, the spinner is debounced, the action is interruptible, and synchronous suspending handlers are supported.pressedChangeActionnow acceptsvoid | Promise<void>.
@astryxdesign/cli
New Features
astryx build: new command for page composition with natural-language search ranking.build "<idea>"returns an agent-ready composition kit grouped by role — a START line (scaffold vs compose), the closest PAGE template, always-on FRAME (page shell) and FOUNDATION (layout/typography/action) primitives, idea-specific BLOCKS and DOMAIN COMPONENTS, and a SETUP reminder. Always-on FRAME/FOUNDATION groups raised measured component recall from 15% → 71% on an agent-grounded eval.buildwith no args prints the how-to-build playbook.- Build-first agent docs: generated
CLAUDE.mdnow leads with thebuildworkflow and includes a required-CSS setup note (reset.css+astryx.css) so components never render unstyled.initpoints agents atastryx build/astryx search. - Denser, tailored agent docs: generated
CLAUDE.md/AGENTS.mdblock tightened from ~48 → ~26 lines (same information), with styling guidance tailored to the project's configured system (StyleXxstyle, Tailwind utility classes, or plainstyle/classNamewithvar(--token)).
Fixes
npx astryxnow works when the CLI is installed as a real npm package. The bin resolves sibling modules via its real path (realpath ofimport.meta.url), fixingERR_MODULE_NOT_FOUNDwhen invoked via thenode_modules/.bin/astryxsymlink. Non-interactiveinit/themeerrors now sayastryx <command>instead of the stalexds <command>.- v0.1.0 upgrade codemod: migrate legacy
@xds/*module specifiers and config surfaces to the Astryx v0.1.0 names. [breaking] Remove legacyastryx.versionFileupdate-hint support frompackage.json.
Documentation
- Theme System guide: add an
npm installstep to Quick Start soimport {neutralTheme} from '@astryxdesign/theme-neutral'doesn't fail withCannot find module(#3082).
@astryxdesign/build
Breaking Changes
- Rename Vite integration exports off the xds name:
xdsStylex→astryxStylex, and option typesXDSVitePluginOptions/XDSVitePluginLegacyOptions→AstryxVitePluginOptions/AstryxVitePluginLegacyOptions. Update imports from@astryxdesign/build/vite. - Rename Next.js helper
withXDS→withAstryx(exported from@astryxdesign/build/next). Updatenext.config.mjs:import {withAstryx} from '@astryxdesign/build/next'.
Contributors
Thanks to everyone who contributed to this release: @cixzhang, @ejhammond, @joeyfarina, @josephfarina, @nynexman4464
Full Changelog: v0.1.0...v0.1.1