Repository navigation
Astryx v0.6.4
Astryx 0.6.4 — all @astryxdesign/* packages ship at this version.
npx astryx upgrade --apply@astryxdesign/core
New Features
-
Add Timer for standardized elapsed durations without React tick renders. (#6438)
UseTimerfor active-operation elapsed time. It starts from mount by default, accepts an earlier Unix-millisecondstartTime, offerselapsedandclockformats with adaptive cadence, and matches Timestamp typography props. -
DialogHeader: expose the start- and end-content wrappers as theme targets (#6415)
Addsdialog-header-start-contentanddialog-header-end-contentso themes can style the existing content-slot wrappers without relying on their DOM positions. The end-content slot also contains the optional close button. Default layout and behavior are unchanged. -
DialogHeadertitleandsubtitlenow accept anyReactNode, not only strings.
A title can carry inline markup and still renders inside the focusableh2that receives focus on open and names the Dialog; the accessible name is the title's text content. A subtitle can carry inline content such as aLink. String callers are unchanged. An empty-string, boolean, or nullish subtitle renders nothing, and a numeric0subtitle now renders inside the subtitle text. -
DropdownMenuItem,DropdownMenuCheckboxItemandDropdownMenuRadioItemforward arefto the row root (#6687).
The ref reaches the element carryingrole="menuitem"(ormenuitemcheckbox/menuitemradio), the wayItemandDropdownMenuDivideralready forward one, so a menu row can be registered with an element-keyed observer or overlay — an IntersectionObserver for an impression, a measurement, a debug outline — without a wrapper betweenrole="menu"and the row. -
Add
presentationto DateInput, DateTimeInput, and TimeInput (spec:AST-043) (#6628).
presentationnames every picker surface, distinguishing Astryx's desktop surface, Astryx's bottom sheet (including a new TimeInput sheet), the browser/OS picker, and — for TimeInput only — a plain typed field. DateInput and DateTimeInput accept five values:'popover' | 'bottom-sheet' | 'native' | 'adaptive-bottom-sheet' | 'adaptive-native'(default). TimeInput accepts those five plus'text-input', the typed field on every pointer, because that is the surface its releasednativePicker="never"already was.presentation="native"always shows native;adaptive-nativekeeps the released native fallbacks.nativePickeris deprecated but keeps working exactly as released (touch→adaptive-native,always→native,never→adaptive-bottom-sheet, ortext-inputfor TimeInput);presentationwins when both are set.astryx upgradeshipsmigrate-native-picker-to-presentationfor static callsites. -
List: addedgeCompensation="inline"to compensate for item content inset within container padding (#2626)
ListIteminsets its content by a density-dependent horizontal padding, so a list under a section heading reads as misaligned and consumers reach for negative-margin custom CSS.edgeCompensation="inline"onListcancels, per inline edge, the smaller of that inset and the container's published padding on that edge; zero-padding and full-bleed surfaces therefore stay in place, asymmetric container padding never over-cancels an edge, and headers, hover backgrounds, and selection backgrounds keep their existing geometry.Itemnow publishes its inline inset as--_item-inset-inlineand derives its ownpaddingInlinefrom it, and the clamped cancelling margin reads the same variable — so the cancel tracks density and theme overrides instead of mirroring hardcoded values. Themes that setpaddingInlineonitemfeed the variable automatically via the derived var registry. -
Markdown: add the first-party soft-breaks plugin (#6459)
UsemarkdownSoftBreaksPluginfrom@astryxdesign/core/Markdown/pluginsto render soft line endings as hard breaks without preprocessing source. The plugin matches the realremark-breakspackage through Astryx's supported adapter path while keeping code and other opaque content unchanged. -
Table: add a selection-aware bulk-actions wrapper that consumes
useTableSelectionStateoutput while keeping the selection plugin behavior-only. (#6474)
Fixes
- Preserve authored heading and text component styles when theme adaptations change the type scale (#6710)
- AvatarGroup keeps its overlap when avatars are wrapped in a HoverCard or Tooltip. Every avatar and the overflow indicator now take the overlap margin, and the group pads its start edge to match, so the overlap no longer depends on each avatar being a direct child of the group (#6736).
- Avatar initials skip punctuation: each word's initial is its first letter, digit or emoji, so
Northwind Workbench (automation)rendersNAinstead ofN(and“Ada” LovelacerendersALinstead of“L. Words with none of those, such as a lone-, are ignored, and a name made only of punctuation shows the default icon rather than a stray symbol (#6698). - Size an Astryx Icon without an explicit size to match its Button or
IconButton: 16px for small and medium controls, and 20px for large controls. (#5762) ChatComposerInput: an empty input no longer shrinks by 8px whenisDisabledflips totrue, which shifted anything bottom-aligned beside it (e.g. a send button in a grid row) (#6654).
The root'sminHeightwas set to the shared line-height only, not the paddingeditableandplaceholderboth add on top of it — normally immaterial, since the editable region reserves its own padded box even when empty. A disabled, emptycontentEditableregion stops reserving that empty line at all in Chromium, and the absolutely positioned placeholder standing in for it doesn't contribute to layout height, so the root fell back to just the line-height and lost the padding.minHeightnow explicitly accounts for both.- ChatComposerInput no longer scrolls for a short single-line draft with
maxRows={1}. Removing vertical padding also keeps the empty input and placeholder aligned when disabled. (#6733) - Keep numeric zero aligned in ChatMessageBubble name and metadata slots. (#6600)
The aligned wrappers are omitted for non-rendering scalar values (null,undefined, booleans, and the empty string), while numeric0remains visible inside the same inset as other slot content. - Render numeric zero when it is passed as the ChatMessageList empty state. A valid ReactNode should not disappear when the transcript is empty. (#6636)
- Omit empty ChatMessageMetadata slots and their separators (#6637).
Boolean and empty-string timestamp or footer values no longer leave a blank row or a stray dot. Numeric zero remains visible, and all delivery statuses keep their existing labels and icons. - Compose accepted
onClickhandlers with ChatSendButton's send and stop actions instead of replacing them (#6653). Consumers that usedonClickto replace sending should move that logic toonSend, because both handlers now run. - Allow long ChatSystemMessage content to wrap within narrow chat layouts instead of crossing the container edge (#6655).
- ChatTokenizedText now ignores empty token values so tokenized messages always finish rendering (#6679).
- ChatToolCalls now displays custom group labels, keeps collapsed details out of keyboard navigation, adds visible focus treatment, and uses readable secondary text for neutral metadata (#6680).
- Stop ChatLayout's scroll-to-bottom button from being a tab stop while it is invisible. At rest the layout's default
scrollButtonrenders hidden, butopacity: 0andpointer-events: noneleave it in sequential focus navigation — so a keyboard user's first Tab into any chat landed on a control with no visible focus indicator (WCAG 2.2 SC 2.4.7), and Enter scrolled the transcript. The hidden state now also setsvisibility: hidden, which the fade transition carries so the animation is unchanged; the visible button keeps its keyboard access. The pill's height and collapsed width now track--size-element-mdinstead of a hardcoded32px, so a theme that retunes the element scale can no longer make the pill clip its own Button. ChatLayout's consumer docs also gain thedensityprop, which was undocumented, and drop the claim that density adapts automatically to container width — it never did. A Chromium evidence spec pins the hidden/visible/re-hidden keyboard contract and the pill's containment of its Button under a size-retuning theme, and the RTL applicability ledger records why ChatLayout and its scroll button have no applicable RTL dimension. (#6466) - Make a theme that styles
chat-layout-scroll-buttonactually restyle the chat scroll-to-bottom pill. The documented target sat on the invisible full-width row that centres the pill, so abackgroundColoroverride painted a band across the chat dock while the pill kept the surface the theme asked to replace — and every automated check passed, because the override did reach an element. The target now rides the pill, which is what paints the fill, elevation, and radius (architecture:component-theming-surfaceINV4). The target keeps its name, stays a single target, and the component's props, DOM shape, ref target, and consumer passthrough are unchanged. A Chromium spec pins the placement and proves the repair by moving the target back and showing the pill go unstyled under a theme. (#6482) - Correct CheckboxIndicator theming, replacement-content, and focus guidance (#6745).
- Align CheckboxInput theming and label-icon guidance with shipped behavior (#6747).
- A CheckboxList option that is saving through
changeActionnow keeps its spinner, busy state, and re-toggle guard when another option is toggled before it settles (#6777). - Clicking a read-only CheckboxList option that has an
onClicknow fires that handler once, instead of re-dispatching the click until the browser's call stack overflows (#6777). - Give inert Citation references a supported accessible name, and document their linked and inert root contract.
- CodeBlock no longer crashes on custom tokenizer types outside the built-in grammar (a dotted type such as
keyword.control.sqlthrew frominsertRuleand took the whole block down). The generated::highlight()name and--color-syntax-*custom property now pass throughCSS.escapebefore entering the dynamic stylesheet, so every type the CSS parser accepts (dotted, digit-led,_private, non-ASCII) keeps its colour, and no token type can reach outside its own highlight rule. A rule the engine still refuses costs that type its colour, never the block. (#5528) Dialogand 30 other components no longer lose theirborderandbackgroundresets in the shipped CSS. The sources used theborder: 'none'andbackground: 'none' | 'transparent'shorthands, which StyleX's default property-specificity mode drops silently, so the declarations never reachedastryx.css; a consumer that does not loadreset.csssaw the UA<dialog>frame. They are now theborderWidth/borderStyle/backgroundColorlonghands. No API change.- Apply the same narrow blocked-scheme rule to native links, custom routers, clickable surfaces, and Markdown links. Rejected destinations stay visible without navigating or invoking a router, including structured URLs with a separate protocol. Ordinary URLs, safe custom schemes, downloads, and accepted router-object identity are preserved; Markdown image/resource policy is unchanged. (#5524)
- Preserve Tailwind font weights when using the theme bridge. (#6479)
- Ignore IME key events (
isComposingorkeyCode229) in useHotkeys, even with allowInInputs enabled, without preventing their default behavior (#6773). - Keep hug-layout segmented controls content-sized in flex containers (#6643)
- Keep a reopened top layer at the front of Escape dismissal order. (#6073)
- Prevent ancestor text formatting and surface/group context from leaking into Layer content. (#6457)
Layer content now starts with theme body typography and neutral text formatting. Core layer content no longer inherits accidental ancestor surface/group membership, including group-owned disabled state, selection, callbacks, and label associations. Intentional groups and required providers created inside the layer still apply. Unrelated contexts, explicit props, themes, and styling overrides remain unchanged. ListwithhasDividersno longer draws a divider after the lastListItem. The last-item reset used theborderBlockEndshorthand, which StyleX's default property-specificity mode drops silently, so it never reached the shipped CSS; it is now theborderBlockEndWidthlonghand. (#6420)- Localize PowerSearch boolean operators in Japanese and Korean and use locale-appropriate ellipses in Chinese. (#6783)
- Markdown: keep lazy continuation lines inside blockquotes and list items (#6752)
Wrapped paragraph lines may omit repeated blockquote markers or list indentation without escaping their owning container. Nested, ordered, unordered, and task-list continuations now preserve their rendered structure, text projection, and source range. - Markdown tables now use the
spacing-2token (8px) on every header and body cell edge. The tighter inline spacing leaves more room for content in narrow reading columns while keeping rows comfortably readable. - Markdown: render escaped table pipes literally in code spans (#6642)
A\|used to keep a pipe inside a table cell now displays as|in inline code, matching prose cells without exposing the structural backslash. Completed inline-code spans render only their parsed contents inside<code>, without source backticks; standalone inline code otherwise remains unchanged. - Markdown: table columns keep a content-derived width floor and headers stop truncating (#6708).
A Markdown table in a narrow reading column no longer squashes every column to a few characters. Each column keeps a floor derived from its own content, measured in characters on the cell's text box, so a column is never narrower than its longest unbreakable token and cell padding does not eat into the floor. Identifiers, URLs, and inline code stay whole, header labels wrap instead of ellipsizing, and a table that is genuinely wider than its container scrolls in Table's own scroll region — which is now the table's only scroll viewport, accessible name, and keyboard stop. - Align titled sections in DropdownMenu and ContextMenu bottom sheets with their spacious action rows (#6694).
- Keep MetadataList side labels readable beside long badges in narrow containers by allowing value columns to shrink, including numeric columns and custom label widths. (#6598)
- PowerSearch:
enum_listvalue menus now show every value instead of the typeahead default of 10. (#6481) - Selector keeps compact single-line triggers aligned with their size tokens, including icons and clear controls.
- Name the no-search bottom-sheet
Selectorlistbox from the component'slabelso Chromium exposes it with an accessible name; the searchable sheet and popover paths keep their existing trigger relationship. (#6395) - Keep Tailwind bridge tokens reference-only so utilities follow the active theme without emitting competing runtime declarations.
- Keep authored theme declarations inside their CSS boundaries. Drop only an unsafe declaration, preserve valid CSS values and legacy token generation, and continue compiling the rest of the theme. Runtime reports dropped declarations on the console; theme builds include them in the existing receipt warnings. CSS generators accept an optional warning-text array for build collectors, without a callback API or additional exported diagnostic types. (#5529)
Documentation
- Document CheckboxList's
isReadOnlyprop, and separate the select-all block example's rows withhasDividersinstead of placing a Divider inside the options list (#6777). - Clarify that CheckboxListItem reads
isCheckedandonCheckinside a CheckboxList withoutvalue(such as a select-all item), and requiresvalueonly when the parent CheckboxList has avaluearray (#6778). - Clarify that CheckIndicator is the selection mark itself and does not render persistent control chrome.
@astryxdesign/cli
New Features
-
Add a reusable Item document tabs block template (#6652)
-
astryx build "<idea>"now always names a page template to start from (#6707).
A page template carries the page frame, the spacing, and the section rhythm. A page composed from components has to rediscover them. Before, the kit recommended scaffolding only when a template matched almost by name. Other ideas got "use it as a layout reference", which pointed at a 35-line--skeleton, and an idea that no template matched got "frame with AppShell, then compose". Now: -
Link docs by identity, and let integrations add to the docs tree. (#6626)
A doc links another doc inside its text with{@link [<provider>:]<kind>:<name>}, such as{@link command:doctor}. The CLI prints each link as theastryx docscommand that opens the doc; a link that names no doc prints as written, andastryx doctorwarns on it. An older CLI prints the link as plain text.reference,workflow, andcollectionblocks stay in namespace docs.An integration can ship namespace docs and place its guides in them. They show up in
astryx docsbesidecli, with the same moves, links, and search, andastryx doctor integration docschecks them before the package ships. A namespace doc in an integration's docs directory no longer fails to load, andastryx integration add doc <name> --parent <namespace>writes a placed guide. A CLI release that does not read the docs tree can hide every doc topic of a package that ships a namespace doc or a placed guide, with nothing saying why, so--parentdeclares the CLI that reads them as an optional@astryxdesign/clipeer, andastryx integration pack --checkfails a package that ships either one without it.The CLI keeps its own routes: an integration's flat topic or namespace named
cli,unorganized, or after one of the CLI's topics (compared without case) is withdrawn from the tree, its name opens the CLI's doc, and doctor warns.Every flat topic now sits in
astryx docs unorganized, under its own name, so every doc has a place in the tree with a way up and across. Search hits for a topic name the level and the package that wrote it.New guide:
astryx docs cli/writing-docs. -
In text,
astryx docs <topic>lists the topic's sections when it has more than one. (#6626)
Read one withastryx docs <topic> <section>, or print the whole topic with--full.--densestill prints the whole dense doc, so the agent bootstrap in AGENTS.md reads the same as before. The JSON contract is unchanged:astryx docs <topic> --jsonanddocs(topic)in@astryxdesign/cli/apistill return the whole topic (docs.detail), and--indexreturns its section list. -
Read the CLI's docs as a tree, one level at a time. (#6498, #6626)
astryx docs clilists the CLI's guides and reference.astryx docs cli/commandslists every command,astryx docs cli/apilists the API's functions, schemas, and enums, and a route such asastryx docs cli/api/functions/searchprints one doc.--jsonreturnsdocs.nodefor a namespace or typed doc, identified by its doc identity (a generated level hasid: null). The text ofastryx docslists the docs tree's namespaces first; its--jsonkeepsdataas the topic list and adds them inmeta.namespaces. Every command, API function, schema, and enum doc the CLI ships declares thenamespacethat reads it:astryx doctorfails when one has none or names one nothing reads, and warns when one has no route in the tree. -
Export
themeTemplate()from@astryxdesign/cli/api, matching the documented API behindastryx theme template. (#6626) -
The integration guide moved from
astryx docs cli-integrationstoastryx docs cli/integrations. (#6626)
Documentation names and routes are mutable catalog data underspec:AST-017/FR45, so the move is nonbreaking and needs no compatibility alias. The guide now lives in the CLI's docs tree, undercli. Useastryx docs cli/integrations, including section reads such asastryx docs cli/integrations components. The old name no longer resolves. The docsite page stays at/docs/cli-integrations. -
astryx searchfinds the smallest doc part that answers. (#6626)
A doc hit is now one section (astryx docs cli/integrations codemods), one docs-tree route (astryx docs cli/api/functions/assert-response), or a topic's index, never a whole-topic read. Typed docs match by their own name and by the identifiers they define, such as error codes.astryx search --type docworks without@astryxdesign/core.astryx docslists the docs tree first, and a namespace shows each child's own name when its route name differs.Every docs read now ends with its moves:
Up, plusPreviousandNextfor a section or a docs-tree page, andRelatedfor a typed doc (its command or API function, and its related docs).--jsoncarries them aslinks(up,previous,next,related). Each search hit carriesparent, the command that opens the level above it, and a docs-tree hit carriespackage. -
A doc section can include another doc instead of copying it. Put a
referenceblock in the section, such as{type: 'reference', target: '@astryxdesign/cli:schema:integration', projection: {fields: ['components', 'docs']}}, andastryx docsprints those two fields of the integration manifest from the schema's own doc, then the command that opens it.
A reference block includes a schema, command, function, or enum doc.projection.fieldskeeps only the named fields of a schema, andpresentationisfull(the default),compact(no code blocks), orsummary. A reference to any other doc shows its title and summary. A read inlines the block, so--jsonstill returns only the stable block kinds.astryx doctor integration docsfails when a block names a doc, field, or projection it cannot include, and a read marks what is missing. Links also find the CLI's authoring schemas now:schema:integrationopensastryx docs authoring integration. -
astryx doctornow fails when a type that@astryxdesign/cli/authoringexports has no doc inastryx docs authoring, or when a listed self-doc documents nothing the package exports. The message names each type, the module that declares it, and the self-doc that is missing or not listed. (#6498) -
Add
presentationto DateInput, DateTimeInput, and TimeInput (spec:AST-043) (#6628).
presentationnames every picker surface, distinguishing Astryx's desktop surface, Astryx's bottom sheet (including a new TimeInput sheet), the browser/OS picker, and — for TimeInput only — a plain typed field. DateInput and DateTimeInput accept five values:'popover' | 'bottom-sheet' | 'native' | 'adaptive-bottom-sheet' | 'adaptive-native'(default). TimeInput accepts those five plus'text-input', the typed field on every pointer, because that is the surface its releasednativePicker="never"already was.presentation="native"always shows native;adaptive-nativekeeps the released native fallbacks.nativePickeris deprecated but keeps working exactly as released (touch→adaptive-native,always→native,never→adaptive-bottom-sheet, ortext-inputfor TimeInput);presentationwins when both are set.astryx upgradeshipsmigrate-native-picker-to-presentationfor static callsites. -
Prepare integration template replacement before its supported package boundary. (#6265, #6626)
An integration template can setreplacesin its own metadata to a Core template id. Unqualified template lookup and discovery surfaces use a valid replacement, while--package @astryxdesign/corestill selects the original. Missing targets, type mismatches, a declaration on a template that cannot be used, and duplicate declarations fail closed and are reported byastryx doctor integration templates.When separate configured packages replace one target, the package configured later wins with a warning. Explicitly configured packages always precede autolinked ones. When only autolinked packages conflict, the dependency listed later in package.json wins with a warning and the CLI recommends explicit configuration. Invalid contribution kinds remain reportable without hiding other valid kinds, and invalid template or component files do not hide valid siblings.
This implementation may ship in final 0.6.x for forward validation, but an integration package that uses
replacesmust still require@astryxdesign/cli >=0.7.0. Earlier CLIs reject the field and withhold that package's templates and doc topics. No supported latest-stable integration consumer can enter the replacement path yet, so replacement selection and its mutable catalog results are patch-compatible pre-publication behavior.Existing same-id
IntegrationTemplateConflictresponses keep their released warning-only shape on 0.6.x. The optionalTemplateListEntry.replacesfield is additive; at or after 0.7.0, replacement-specificrelationship,replaces, andseverity: 'info'conflict fields require one deliberate projection update across runtime, types, generated reference, terminal output, documentation, and tests. A package-version bump alone leaves the warning-only shape unchanged. -
Add ScrollableArea block templates so the component page has worked examples. All six share one content vocabulary — a workspace file panel of labelled sections holding a two-column grid of muted cards — so the only thing that changes between examples is the behavior each one demonstrates: block-axis scrolling,
axis="inline"withisFullBleed, sticky section labels,axis="both", sticky pass-through againststickyContainment="always", andoverscrollallow against contain. (#6490) -
Add the Tree Table page template (#6195)
A hierarchical table where every parent row is derived from its children, shown as a code repository: folders roll up the newest commit beneath them, columns resize, sorting is scoped to siblings so branches never interleave, arrow keys walk the tree per the APG treegrid pattern, and search prunes to the branches that match. Selecting a folder drives a header trail that folds its middle into a menu once the path outgrows the bar. Supporting repository chrome — header actions, an About sidebar and a README rendered withMarkdown— puts the table in the context that makes its rollups legible. -
Add opt-in typed documentation graph contracts and stable provider-aware documentation identity without breaking existing topic readers. (#6471)
NewNamespaceDoc,AuthoredDocKind, provider identity types, semantic graph-block types, section IDs,astryx docs <topic> --index, and section-key reads are additive. The publicReferenceContentBlockunion keeps its 0.6.x members so existing exhaustive renderers continue to compile; graph-onlyworkflow,collection, andreferenceblocks are exported separately asGraphContentBlockand are accepted byNamespaceDoc.Existing authored topics continue to load and read as before. Duplicate title-derived keys receive deterministic suffixed index keys, titles with no Latin letters or digits receive deterministic
section-Nkeys, ambiguous title queries keep returning the first match, and legacy extension sections without IDs continue to merge by exact title. Explicit new section IDs remain validated. The new progressive-disclosure Doctor audit reports compatibility issues as warnings, and existing full-topic text output keeps its 0.6.x formatting.Every doc section can opt into a stable
id.astryx docs <topic> --index(docs(topic, undefined, {index: true})) returns the topic's section index (docs.index), andastryx docs <topic> <key>reads one section. A topic read still returns the whole doc.astryx docs authoringdocuments every authoring schema, one section each.Provider-ID conflicts are now visible instead of being dropped without a word: the package being authored wins, otherwise the first-loaded provider wins, and every command plus
astryx doctorreports the set-aside package. -
Integration themes use typed same-stem descriptors, not a central catalog. (#6498)
A themes root no longer holdsmanifest.json, the theme catalog thatastryx integration add themewrote in 0.6 (stable since 0.6.3). Each theme carries a strongly typed<name>Theme.doc.mjsbeside its source instead, and a themes root that still holds the catalog is refused. To migrate an integration package, runastryx upgrade --from 0.6.3 --path . --applyin it: a codemod writes each theme's descriptor from its catalog entry and removes the catalog. Until a package is migrated, apps that install it get none of its themes or doc topics.Theme discovery reads descriptors and checks integration theme sources without executing them, and
theme addcopies an integration theme's complete directory.astryx doctor integration validatewarns about a folder in the themes root that looks like a theme but is not read as one. New component, topic, and template scaffolds also emit type-annotated.doc.mjs; released.template.*inputs remain readable.
Fixes
-
The published authoring types now type-check in projects that use
"moduleResolution": "nodenext"or have no Node types installed. Relative imports inside them name their files, andPostCodemodCommand'senvno longer needs Node's types. (#6492) -
Drop
gpt-tokenizerfrom the CLI's peer dependencies. Nothing in the CLI imports it, but npm and pnpm install a required peer by default, so every install of the CLI pulled in about 53 MB it never used. (#6508) -
astryx init,astryx init --remove-agentsandastryx upgrade --applyno longer edit or delete a file outside the project through an agent file or.claude/directory that is a symlink pointing there. Init reports a path-safety error for that file and exits 1,init --remove-agentsfails withERR_PATH_TRAVERSALand exits 1 instead of reporting the block removed, and upgrade reports the refresh as failed, before any file is written. (#6524) -
The text output of
astryx componentandastryx hookno longer adds non-ASCII characters of its own. Empty table cells show-instead of an em dash, the brief view's import hint reads<- from, derived properties and deprecated targets use->, and brief prop and parameter lists are separated by commas instead of middle dots. Text that comes from the docs themselves is unchanged. (#6553) -
astryx inithuman output is now plain ASCII, including the per-file linesinit --remove-agentsprints. Status lines use[ok]instead of a check glyph, and dashes, bullets and arrows print as-and->.--jsonoutput is unchanged. (#6540) -
astryx upgradehuman output is now plain ASCII. Progress and codemod lines use[ok],!and!!instead of check, warning and cross glyphs, and dashes and arrows print as-and->, including in codemod titles listed by--list.--jsonoutput is unchanged. (#6539) -
Commands that write files no longer follow a dangling symlink out of the project: when the target, or a directory on the way to it, links to a missing path outside the project root, the command now fails with
ERR_PATH_TRAVERSALinstead of creating the file there. A symlink escape reported byintegration addnow carriesERR_PATH_TRAVERSALtoo, instead of an unregisteredPATH_TRAVERSALcode. (#6513) -
astryx blogtext output now labels the feed URLfeedUrl, matching its--jsonkey, and prints every post field the JSON carries: the list adds each post's description, date, authors and link, and a post read adds its metadata above the body. (#6526) -
astryx build "<idea>"no longer prints asetup:line in its text output. That field existed only in the text, never in the--jsonkit, so the two views disagreed. The same guidance is in the no-queryastryx buildplaybook. (#6570) -
astryx build --jsonwith no query, andbuild()with no query, now return the playbook itself — a title, the ordered steps with their commands, the on-system rules, and related lookups — instead of only{playbook: true}. The terminal output is rendered from the same data, andplaybook: trueis still there. (#6566) -
The programmatic
component()API now rejectsdetailandlangvalues that theastryx componentcommand rejects, with the same codes (ERR_INVALID_DETAIL,ERR_INVALID_LANG). It used to fall back silently: an unknowndetailreturned the name list, and an unknownlangreturned English. (#6576) -
The programmatic
component(name, {cwd, blocks: true})now discovers blocks from thecwdit is given, as every other slice already does. It used to read blocks from the process working directory, so a caller pointing at another project got that directory's blocks, or none. (#6580) -
parentDocinastryx component <Name> --jsonis now a documented part of thecomponent.detailresponse. The field appears when a sub-component such asHStackis scoped out of its parent's doc. It is in the published response type and thecomponent()reference, and the text output now shows it asparentDoc: Stack. (#6575) -
astryx component <Name>no longer prints a "Related block templates" list that--jsonnever carried, so the text output shows only what the JSON result holds. The same blocks are still listed byastryx component <Name> --blocks, in text and JSON. (#6574) -
astryx component <Name> --package <pkg>no longer ignores--sourceand--blockswhen the package publishes docs through the legacyastryx.docsfield.--sourcenow fails withERR_NO_SOURCE, and--blocksreturns the blocks, the same answers as without--package. Before, both flags silently returned the plain doc. (#6577) -
astryx component --listnow prints the right import for components from packages that publish docs through the legacyastryx.docsfield. It used to show an@astryxdesign/corepath for them. The JSON list entries now carry the sameimportthatastryx component <Name>reports for each of those components. (#6578) -
astryx integration add component <Name>now refuses withERR_FILE_EXISTSwhen a component doc anywhere under the components root already uses that name, for examplecomponents/<Name>/<Name>.doc.mjs. Before, it wrote a second<Name>beside the first and reported success, andastryx component <Name>then showed the new scaffold instead of the authored component.--dry-runrefuses the same way. (#6557) -
The
debugentry of theAstryxConfigtype and ofastryx docs authoring confignow states how handlers from integrations combine with the app's own: the app's runs first, then each integration's in load order, a handler that throws is skipped without affecting the others or the command, and{"astryx": {"inheritDebug": false}}refuses inherited handlers. The type no longer claims that leavingdebugout records nothing. (#6514) -
The text output of
astryx discover(the package list and a single package) now shows every field its--jsonentry carries, includingcategoryandversion, which only the JSON used to include. (#6521) -
astryx doctortext output now uses the same field names as--json: each check prints itsidandlabel(the label was shown ascheck, and the id was missing), and the summary printspass,warn,fail, andinfounder asummaryheading instead of a prose line. (#6516) -
astryx template --helpandastryx layout expand --helpnow explain how the path argument is read: a path ending in a source-file extension is the file to write, anything else is a directory that getspage.tsx, the block's file name, or<Name>.tsx.layout expandandlayout checkalso document-for stdin and that--filewins over the argument, and--overwriteno longer mentions a prompt the CLI never shows. (#6571) -
The CLI no longer reads or sets the
ASTRYX_LATEST_VERSIONenvironment variable. Its only effect was anFYI: A newer version of @astryxdesign/core ...line on stderr afterastryx componentandastryx docs, and a CLI run cannot set a variable for later runs, so the line appeared only when the variable was set by hand. Commands now print the same output whether or not it is set. (#6554) -
The
@astryxdesign/cli/jsontypes now declareapiVersiononCLIError,CLIUnsupportedError, and the success envelope thatparseResponseandassertResponsereturn, matching what every--jsonenvelope carries. Code that constructs aCLIErrorvalue by hand, for example in a test double, now has to includeapiVersion. (#6555) -
astryx <command> --help(includingastryx manifest --help) now ends with the command's documented exit codes, and each command inastryx manifest --jsoncarries them asexitCodes: [{code, when}].astryx doctor --helpshows them once, and thelayoutanddiscoverexit codes now say when they apply: bareastryx layoutexits 1, and a blankdiscoverquery exits 1 when packages are discovered. (#6586) -
astryx gap-report --helpandastryx manifestnow describe thecomponentargument and say thatcomponent,--category, and--reasonare required unless--list-categoriesis set, with the character limits the command enforces. The manifest listed the argument with an empty description, and nothing said these inputs were required. (#6518) -
astryx theme buildnow fails withERR_THEME_INVALID, before writing anything, when a custom Heading type's standalone rule has no usable declaration: every value is blank, or the compiler dropped every declaration. It previously wrote CSS with an empty or missing rule and still added the type to the generatedHeadingTypeMap. (#6547) -
With
--json,astryx help <unknown-command>and a command group run without a subcommand (such asastryx layout --json) now return an error envelope, withERR_UNKNOWN_COMMANDorERR_MISSING_ARGUMENT, instead of a success-shaped help envelope. Both still exit 1, as they do without--json. (#6550) -
astryx hook <name>text output no longer lists block templates that the--jsonenvelope does not carry. It now names the related components and points toastryx component <name> --blocks, which returns their block templates as JSON. (#6537) -
"astryx": {"inheritDebug": false}in package.json now also refuses thedebughandler of an autolinked integration in a project that has noastryx.config. The setting used to be read only beside a config file, so without one those handlers still received every run. (#6520) -
Programmatic
init()now confines the starter template it scaffolds withtemplateNameto the project directory. Asrcsymlink that points outside the project is rejected withERR_PATH_TRAVERSALbefore anything is written. (#6538) -
astryx integration add --helpand the CLI manifest now define every control: the name format for each kind, that--typedefaults topage, that--totakes an exact semver version, and that--replacesand--extendscan't be combined. TheintegrationAdd()docs say the same. Behavior is unchanged. (#6558) -
One integration that cannot load at all (a configured package that is not installed, has no manifest or more than one, or a package being authored with two manifests) no longer takes every other integration down with it. It is reported as that package's integration issue, the other integrations keep contributing, and
astryx discoverno longer exits 1 because of it. (#6519) -
One integration whose templates root cannot be read, for example a manifest that points
templatesat a file, no longer makesastryx templatefail with a raw filesystem error. That package's templates are skipped with the usual one-line warning, and core templates and every other integration's templates still list and resolve. (#6523) -
The
--jsonoption's description inastryx --help, in the manifest, and in the CLI README now lists every envelope field:{ apiVersion, type, data, meta? }on success and{ apiVersion, error, code, suggestions? }on failure. It used to omitapiVersion,meta, and the stablecodefield that consumers branch on. (#6549) -
astryx layout expand <expr> <dir>now refuses the write, withERR_PATH_TRAVERSAL, when<dir>/<Name>.tsxis a symlink to an existing file outside the project. Before, only the directory was checked, so the generated TSX replaced the file the link pointed at. (#6564) -
astryx layout expand <expr> <path>now labels its text fieldscomponentsUsedandtodos, the keys the--jsonoutput uses, instead ofComponentsandTODOs. (#6569) -
astryx layout expandnow caps every*Nrepeat at 10000 copies. Repeated table rows skipped the cap, and a huge count on any element was still walked copy by copy before the cap applied, soB*999999999could hang or run out of memory.astryx layout grammarnow states the cap. (#6565) -
astryx layout check -andastryx layout expand -now stop reading stdin at 5 MB and fail withERR_INVALID_ARGUMENT, the same size cap--filealready had. Before, an endless or oversized pipe was buffered whole until memory ran out. (#6572) -
When a command's module fails to load, running that command with
--jsonnow prints one error envelope (ERR_UNKNOWN, with the load error in the message) instead of printing nothing to stdout. Without--jsonthe error is still printed to stderr, and the exit code is still 1 in both modes. (#6551) -
astryx manifestwithout--jsonnow labels each command's namename:, the same key the JSON manifest uses, instead ofcommand:. (#6552) -
astryx theme build --outnow reports a path that leaves the working directory withERR_PATH_TRAVERSAL, and an output directory it cannot create withERR_WRITE_FAILED, instead of unregistered codes such asPATH_TRAVERSALorEEXIST. The programmaticthemeBuild()throws the same codes as anAstryxError. (#6543) -
astryx theme palette generatenow writes candidate JSON in the canonical form theastryx-oklch-v1recipe pins, so a JSON candidate and thecandidateSha256in its receipt match the recipe's reference fixtures byte for byte. Before, thestopsarray was printed on one line, which changed the bytes and the digest of every JSON candidate. (#6531) -
astryx theme palette generateandgenerateTonalPalette()now reject aneutralProfilethe recipe does not define, even when the request has no neutral family. Before, such a request produced a candidate whose receipt recorded the unknown profile as part of the normalized request. (#6534) -
astryx theme palette generatenow reports an output or preview path it cannot use, such as one below a regular file, with the stableERR_WRITE_FAILEDcode. Before, the--jsonerror envelope carried the raw system error name, such asENOTDIR, as itscode. (#6533) -
--jsonoutput is one envelope again whenastryx.configor an integration manifest prints while it loads. Anything a project module writes to stdout during its load now goes to stderr. (#6581) -
A
--jsonerror envelope'scodeis now always one of the documented error codes. A failure that carried a Node.js system code, such asENOTDIRorEACCESfrom a failed write, used to put that code in the envelope; it now reportsERR_UNKNOWN, and the original message is unchanged. (#6548) -
The 0.6
rename-resizable-pixel-boundsupgrade codemod now also renamesminSizePx/maxSizePxin static inlineuseResizableconfigurations called through a namespace import (Astryx.useResizable({...})) or wrapped inas constorsatisfies. These were left unchanged before. (#6541) -
astryx searchnow fails withERR_CORE_NOT_FOUND, likecomponentandhook, when@astryxdesign/corecannot be found, instead of the catch-allERR_UNKNOWN. (#6525) -
astryx search --limitnow refuses a value that is not a positive integer, such as1.5or5abc, withERR_INVALID_ARGUMENTand exit 1, assearch({limit})already did, instead of silently truncating it. (#6528) -
astryx searchtext output now prints every field its--jsonresults carry:titlefor doc results andkindfor template results were missing. The--verbosehelp now says what it adds: each result's score and match reason. (#6527) -
search()from@astryxdesign/cli/apiis now declared to returnSearchResponse, as its docs say, so TypeScript sees each result'sSearchResultEntryfields instead of a bareobject. (#6529) -
astryx swizzleno longer writes outside the project through a symlink in the output folder. When the component folder or one of its files is a symlink that points outside the project, the command now fails withERR_PATH_TRAVERSALbefore it writes anything. (#6573) -
The
astryx swizzle --overwritehelp and manifest entry no longer says it skips a prompt. The CLI never prompts. The entry now says that without--overwrite, existing files fail the command withERR_FILE_EXISTSand nothing is written. (#6579) -
astryx template <name> <dir>now refuses the write, withERR_PATH_TRAVERSAL, when the file it would create in that directory is a symlink to an existing file outside the project. Before, only the directory was checked, so--overwritefollowed the link and replaced the file it pointed at. (#6563) -
astryx template <name> <path>andastryx layout expandnow replace demo media only when a path starts with/template-assets/, so third-party URLs and product paths that merely contain that text are left alone. Demo media in a subdirectory, with a query string, or with characters such as@in the file name is now replaced whole instead of being corrupted or left behind. A demo media reference that cannot be replaced safely, such as one with no file suffix or one built at runtime, now fails the copy with its path. (#6596) -
astryx theme addnow copies every file a theme catalog lists byte for byte, so a theme that ships a font or an image arrives intact. Before, it decoded each file as text, which corrupted any file that was not UTF-8. (#6530) -
astryx theme addno longer writes through a symlink that already sits at the temporary name it stages each file under. A link that leads outside the project now fails withERR_PATH_TRAVERSAL, and any other entry at that name fails the copy instead of being overwritten. (#6535) -
astryx theme buildandastryx theme palette generatenow print plain ASCII: status lines use[ok],[warn],[error],[fail], and[note]markers instead of symbol glyphs, and theme build messages drop em dashes and ellipses. The reworded font and private-variable messages also appear in the--jsonreceipt'snoticesandwarnings. Generated theme files are unchanged. (#6544) -
astryx theme build --helpand the capability manifest now state each flag's default and which flag combinations are refused (--familywith--outor--watch,--checkwith--watch,--watchwith--json,--outwith more than one file), with the error code the refusal returns. (#6546) -
The
themeBuild()reference and thetheme.buildresponse-type entry (and the CLI README table generated from it) now document every field of the receipt by name, includingnotices, the advisories (such as a font the theme names but does not load) that had no documentation. (#6545) -
astryx theme templatenow reports a file it cannot write with the stableERR_WRITE_FAILEDcode. Before, the--jsonerror envelope carried the raw system error name, such asEEXISTorEISDIR, as itscode. (#6532) -
astryx upgrade --jsonnow prints exactly one JSON envelope when a post-codemod hook prints output. Anything a hook'sbuildCommandwrites goes to stderr, so stdout carries only the result. (#6536) -
The published
UpgradeListEntrytype now declaresoptional, the boolean everyastryx upgrade --list --jsonentry already carries, so typed callers can read it without a cast. (#6542) -
astryx doctor integration validate,templates,components, anddocsnow show theinvalid_package_jsonerror when a local integration's package.json can't be parsed. Before, the text output said noastryx.integration.*file was found and hid the error, because the JSON reported a nullname, which means no manifest. In that casedata.nameis now(local package). (#6559) -
astryx docs authoringnow says which docs-graph features are not built yet: theplacement,aliasesandaudiencefields, the workflow, collection and reference blocks, namespace docs, and the artifact, doc and instance identities. It had described them as working, but a topic that uses them fails to load. A namespace doc in an integration's docs directory now fails with a message that names it, instead of reporting missing topic fields. (#6492) -
astryx doctor integration validatenow ends each finding about a misplaced contribution, a stray codemod file, a mis-named codemod folder, a component doc without its source, or a component source without a doc with a fix that works when followed as written: where to move the file and the manifest line to add, the version folder a codemod belongs in, or the file to add. Codemod files are named by their path inside the package instead of an absolute path. A hidden component doc no longer draws the missing-doc warning, and a codemods root at the package root no longer reports the manifest as a stray codemod. (#6498) -
An integration topic that
extendsanother no longer renames it.astryx docs themewith an extension installed used to print the extension's own title and description; the topic now keeps its own, and the extension only adds or replaces sections. A topic thatreplacesanother still renames it. (#6498) -
Use extensionless subpath specifiers for generated integration imports (#6288)
integrationAddComponentandintegrationAddTemplatenow emit extensionless public import specifiers (@pkg/components/MyWidgetinstead of@pkg/components/MyWidget.tsx) and map them to source files through the packageexportsfield. Consumer imports no longer expose the package's source extension or requireallowImportingTsExtensions.integrationPackChecknow rejects public specifiers ending in.tsxor.tsand validates each exact import from the packed artifact through Node's package resolver. Packages without a usable public export fail the check, and the result does not depend on project-local TypeScript. -
Make every command's text output match its --json data (#6616)
upgrade --listtext now renders each codemod from the JSON result (name, title, version, optional) instead of the API logger, with no(undefined)rows.theme targetsprints one line per target via the formatter kit's inline layout and now shows className.docslist shows the package field. A manifest-driven parity test covers the commands this PR fixes and catches future regressions in the same family; commands with known deferred divergences are covered by envelope and exit-code checks and have allowlist entries that explain the gap. -
Correct the palette authoring types.
TonalPaletteCandidate's description had landed onTonalPaletteAnchor, so the generated.d.tsdocumented the wrong type and left the candidate bare.TonalPaletteFamilyInput— the type an author writes by hand — had no property descriptions, andneutralProfilenever said what its four values do. (#6168)
[fix] Give the generation receipt a real type.generationReceiptwasRecord<string, unknown>; it is nowTonalPaletteGenerationReceipt, withTonalPaletteRampDiagnostics,TonalPaletteCoordinationDiagnostics, andTonalPaletteNormalizedRequestbeside it. The generator's internal typedefs point at the same types, so the compiler holds the documentation true instead of letting it drift.[docs] Replace the stale
xdscommand name withastryxacross 79 lines of API type docs in 11 files, and realign the invocation tables. Codemods and changelogs that reference the old name are untouched — migrating it is their job. -
Protect generated, vendored, ignored, linked, dependency, and out-of-root files from upgrade codemods using working-tree declarations. Upgrades now run declared regeneration hooks, recheck protected outputs, and report incomplete changes in human and JSON results (#6692).
-
Restrict the authoring factory codemod to Astryx imports (#6335)
-
Restrict the status-variant and Avatar-size upgrade codemods to static props on verified imported JSX components, avoiding unrelated literal rewrites. (#6445)
-
Test and fixture files under a codemod version folder are no longer loaded as codemods. Every
.ts/.mjs/.jsfile under a version folder was loaded and validated, so a test colocated with its transform failed validation and — a definition error being a hard error — took every codemod in that version with it, whileupgradeapplied nothing and reported success. Reserved names:*.test.*,*.spec.*,*.fixture.*, and anything under__tests__/or__fixtures__/. (#6230) -
A stamped component doc (
type: 'component') that documents several components withcomponentsnow loads, as the publishedComponentDoctype allows. It used to fail with "props: expected array". Each entry must name its component; an entry without anamefails at load instead of later in a reader. (#6492) -
Keep authored theme declarations inside their CSS boundaries. Drop only an unsafe declaration, preserve valid CSS values and legacy token generation, and continue compiling the rest of the theme. Runtime reports dropped declarations on the console; theme builds include them in the existing receipt warnings. CSS generators accept an optional warning-text array for build collectors, without a callback API or additional exported diagnostic types. (#5529)
-
Make the Toolbar — Table Filter block's filters actually filter, and bring the row up to the pattern the Filterable Table page template demonstrates: each closed selector doubles as its own filter chip, clauses fold from the end into a count as the row narrows, and the result count, clear all, and a column picker follow the clauses. (#6478)
Documentation
astryx docs authoringnow documents theDebugEventadebughandler receives and theGapReportHandlercontract, field by field. Both types were exported from@astryxdesign/cli/authoringwith no section of their own. (#6498)astryx docs authoringnow matches the published authoring types field for field, and a test keeps it that way: every field is listed, with its real type and whether it is required. Three entries were wrong: a component doc'susageis optional on sub-component docs, a command option'sdefaultmay also be a boolean or a list, and a codemod'stypeis'code'or'config'. (#6492)- Document CheckboxList's
isReadOnlyprop, and separate the select-all block example's rows withhasDividersinstead of placing a Divider inside the options list (#6777). - The documented exit codes for
astryx buildnow say that a query exits 1 when@astryxdesign/corecannot be found, while the playbook (astryx buildwith no query) needs no core. (#6592) astryx discover --componentsis now documented as what it does: in the package list it prints every component of each package instead of the first 10 and a "+N more" count, and it changes nothing in--json. It was described as "List components only". The help also gains an example. (#6522)astryx init --helpand the manifest now say how init's flags interact:--remove-agentsonly removes the managed block and ignores the install flags,--alloverrides--features, and--agentand--agent-docs-pathapply only when agent docs are installed, with an explicit path taking precedence. The documented exit codes now include an--agent-docs-pathoutside the project (exit 1) and no longer list two template cases the CLI cannot reach. (#6589)astryx theme add --overwriteandastryx upgrade --install-depsno longer describe a prompt the CLI never shows; each now says what happens without the flag (ERR_FILE_EXISTSwith nothing written, orERR_DEP_MISSING).ERR_FILE_EXISTSis described as "Refused to overwrite an existing file." without the "non-interactive mode" qualifier; its meaning is unchanged. (#6593)- The CLI README now shows
apiVersionin every hand-written envelope shape and example, and listsastryx search --verbosein place of--detail, which needs a level and does not add a result's score or reason. (#6587) - The response-type docs, and the CLI README table generated from them, now name the fields of the
component.detail,docs.index,search,build.kit,gap-report.file,theme.build,theme.targets, andintegration.pack-checkresponses by their JSON keys, includingparentDoc,hint,notices,deprecatedFor, each gap-report delivery's fields, and the pack-check contribution identities and issue fields. Thecomponent.detailresponse type declaresparentDoc. (#6588) astryx template --helpand the manifest now say which flags win when they are combined:--cdnoverrides everything else and writes to its value, else to<path>, elsecdn.template.html;--listignores a name, a path,--skeletonand--overwrite; and--skeletonneeds a name and writes nothing. (#6591)astryx upgrade --helpand the manifest now state how its flags combine:--listignores every other flag,--registryrefuses--listand the migration flags, and--codemodis the only way to run an optional codemod and also skips the ShadCN composition check. The--fromhelp names the legacy@xds/corefallback, and the documented exit codes now include a missing core, a missing jscodeshift, an invalidastryx.config, a post-codemod hook failure and the refused flag combinations. (#6590)astryx docs authoringnow says where loading a doc is looser than its published type (stamped component and function docs, older generic docs, and templates), and which doc kinds accept fields they do not know. Nothing about how docs load has changed. (#6492)
Other Changes
-
startnames the template to scaffold, with thetemplate <id> --type page <path>command that selects it (an integration replacement through the Core id it replaces), abasis, a one-linereason, andalternatives: the next two templates. A page ranker built for the long ideas builders write ("ops dashboard with a KPI row, a sortable table and a trend chart") picks it. Every matched word counts, weighted by how rare it is among page templates. The words before the first "with", ":" or "," name the page's family, a container ("in a modal") names its frame, and a word that only modifies another ("product" in "product response") counts half. A family's base template (dashboard,settings) leads its family unless a variant's own words outweigh it. Family words come from the templates' own ids.basisisdirectwhen the ranker's pick is also search's direct match,closestwhen it is not, andfallbackwhen nothing has the evidence to lead and the page starts from theshell-top-navapp shell (blankwhen that is not available). A template that is not ready yet is never the start. -
Search matches words more strictly. A term matches inside a name or keyword only at the start of one of its words ("input" finds
TextInput, "file" no longer finds "profile"), plurals and stems count as the same word, and typo tolerance applies only to one-word lookups of words long enough that one edit rarely makes another word ("site" no longer matches "side", nor "cable" "table"). -
Blocks and components that matched only one description word of a multi-word idea are no longer offered.
-
The text output has four sections: TEMPLATE (with its reason and command), OTHER TEMPLATES, BLOCKS, and COMPONENTS (with the frame and foundation names). They replace RECOMMENDED START and PAGE TEMPLATES. Search's page matches (
pages) move to one line, with their full entries under--verbose. Descriptions stop at their first sentence, and blocks and components show the top three, each with one shared command line.--verboseshows every block and component, with full descriptions, import paths, and match reasons. The recommended command always scaffolds (template <id> --type page <path>), where for most ideas it used to print a--skeletonorcomponent AppShell.The
buildplaybook, the generated agent docs, and theworking-with-aiandlayoutguides now start every page from a template.Compatibility: the
build.kitJSON only gainsstart. Every existing field keeps its shape and meaning. Which pages, blocks, and components are listed, anddirectMatch, change with the stricter matching, as ranking results do. The human-readable output is reorganized. Options, exit codes, and thebuild.helpshape are unchanged, andbuildstill writes nothing. The same matching changes the ranking ofsearchresults. -
Docs reads go through one internal compiler.
astryx docs(anddocs()),astryx doctorandastryx searchread compiled topic nodes instead of each loading, merging, translating and linking doc files on its own. Output is unchanged. (#6484)
@astryxdesign/build
Fixes
- Keep PostCSS and Vite processing inside
@astryxdesign/build's declared dependency boundary (#6605)
Packed consumers no longer depend on workspace hoisting to find PostCSS helpers or CSS compatibility processors. The package now owns Autoprefixer, Browserslist, and Lightning CSS, and a clean isolated-install test exercises the published tarball's PostCSS helper and Vite output. - Make source builds fail on unsupported StyleX declarations and load shared StyleX output from every Vite HTML entry.
Nested pseudo-elements andstylex.keyframes()now have production-build regression coverage, and the maintained capability registry tracks the installed StyleX version.
@astryxdesign/theme-butter
New Features
- Ship a typed
ThemeDocdescriptor beside each first-party theme source. (#6498)
@astryxdesign/theme-chocolate
New Features
- Ship a typed
ThemeDocdescriptor beside each first-party theme source. (#6498)
@astryxdesign/theme-gothic
New Features
- Ship a typed
ThemeDocdescriptor beside each first-party theme source. (#6498)
@astryxdesign/theme-matcha
New Features
- Ship a typed
ThemeDocdescriptor beside each first-party theme source. (#6498)
@astryxdesign/theme-neutral
New Features
- Ship a typed
ThemeDocdescriptor beside each first-party theme source. (#6498)
Documentation
- Describe Neutral as Figtree typography and add the font-loading snippet; the README claimed system fonts while the theme declares Figtree. (#5991)
@astryxdesign/theme-stone
New Features
- Ship a typed
ThemeDocdescriptor beside each first-party theme source. (#6498)
@astryxdesign/theme-y2k
New Features
- Ship a typed
ThemeDocdescriptor beside each first-party theme source. (#6498)
Contributors
Thanks to everyone who contributed to this release:
@AKnassa @bhamodi @cixzhang @ejhammond @ernestt @fullstackhacker @harjothkhara @HelloOjasMutreja @humbertovirtudes @imdreamrunner @jiunshinn @josephfarina @korkt-kim @ksying @kyu-rong @light-merlin-dark @nynexman4464 @rubyycheung @vjeux
Full Changelog: v0.6.3...v0.6.4