v16.5.0-canary.3
- Document
next analyze exportand skill are added in 16.4: #99738 - create-next-app: write agent feedback block to AGENTS.md when enabled: #99813
- [turbopack] fix some unused dependencies: #99825
- Fix next-bundle-optimizer skill handoffs: #99818
- [ci] Increase deploy test concurrency to 8: #99770
- Upgrade React from
278794d7-20261002tod75b0697-20261006: #99819 - Turbopack: fix turbo-trace-size test after MemorySample gained active_worker_threads: #99824
- Turbopack: batch EsmBinding codegen: #99722
- Turbopack: add no-memory flag to NEXT_TURBOPACK_TRACING: #99777
- Turbopack: add turbo-trace-size CLI to inspect trace file size: #99765
- Use ESLint 10 in new create-next-app projects: #99814
- Fix instant codemod matching colocated test files: #99795
- turbo-trace-server: speed up loading compressed traces: #99775
- Upgrade rustc to nightly-2026-10-04: #99682
- Bump to swc v81: #99720
Huge thanks to @wbinnssmith, @aurorascharff, @kassens, @eps1lon, @sokra, @mischnic, and @devjiwonchoi for helping!
@astrojs/netlify@8.2.8
- #18180
6fb83daThanks @matthewp! - Fixes Netlify Image CDN patterns generated fromimage.remotePatternspathnames ending in/**so they only match paths below that directory, consistent with Astro's own pattern matching. Previously, a pattern like/public/**also matched sibling paths sharing the prefix, such as/public-assets/. - Updated dependencies []:
- @astrojs/underscore-redirects@1.0.4
astro@7.3.7
-
#18266
cba76ccThanks @astro-factory! - Fixes a build error when a Markdown content collection entry loaded withglob({ deferRender: true })has alayoutfrontmatter property.layoutis now ignored for content collection entries, as documented. -
#18287
38f6793Thanks @astro-factory! - Fixesastro add cloudflarefailing to install dependencies with pnpm v11+ by approving theworkerdbuild script, and shows the package manager's error output whenastro addfails to install dependencies -
#18222
fcf6ed6Thanks @mingjunlu! - Fixes an issue where AVIF images were served asimage/heifinstead ofimage/avifin the dev server. -
#18240
de4df06Thanks @astro-factory! - Fixes thecache()handler fromastro/honoandastro/fetchthrowing aTypeErrorwhen a cache provider is configured. It now registers the cache provider before rendering, soAstro.cacheis available to downstream handlers likepages(). -
#18268
547b572Thanks @astro-factory! - Fixessecurity.checkOriginrejecting cross-origin requests with non-form content types such asapplication/json. As documented, the check only applies to unsafe requests that have nocontent-typeheader or one ofapplication/x-www-form-urlencoded,multipart/form-data, ortext/plain.
@astrojs/language-server@2.17.2
- #18110
ffdf774Thanks @Princesseuh! - Fix organize imports for Astro files whose frontmatter ends with imports.
Astryx 0.6.6
Astryx 0.6.6 — all @astryxdesign/* packages ship at this version.
npx astryx upgrade --apply
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry. -
BottomSheet is a container, like Dialog. A new
paddingprop takes a spacing step, and a theme'spaddingonbottom-sheetnow pads the sheet's content box through container tokens instead of padding the panel. The padded content box publishes its inset, so a Section that is the sheet's only child, and bleed children such as Table and Divider, align against it. With neither set, the content box stays unpadded as before. -
ComplexSelectorcan hang off a control the caller renders. A newrenderTriggerrender prop renders the control the popup hangs off — a glyph in a list row, a chip, an icon button — in place of the selector's own field and button. Spread the given props onto it; the popup is anchored to it, keeps its dialog label fromlabel, opens on click or ArrowDown, and returns focus to the control on close. The existinghandleRefandonOpenChangework unchanged beside it. Off by default; existing selectors are unchanged. -
ContextMenu takes
triggerAs(div|span) so a reference inside prose can own a context menu without breaking the text flow. -
Export the canonical 56-token StyleX
dataVarsgroup for CSS-capable data visualization consumers. -
Export
decodeMarkdownCharacterReferencesfrom@astryxdesign/core/Markdown/parserand@astryxdesign/core/MarkdownIt decodes character references the wayMarkdownrenders them —©,©, and©become©; unknown names and references without their semicolon stay as written — using the same tableMarkdownuses. It works on plain text, so leave code and backslash-escaped references out. The parser subpath has no use-client boundary, so server code can call it. -
Add
DropdownMenuGroup, a titledrole="group"of rows for compound-mode menus. Theitemsdata API could title a group ({type: 'section', title, items}); a menu written with children — checkbox rows, radio groups, rows mounted only while open — could not.DropdownMenuGroup(alsoContextMenuGroupandBreadcrumbMenuGroup) renders arole="group"named by its heading througharia-labelledby; the heading shares the data mode's typography andastryx-dropdown-menu-section-headingtheme target, is not a menu item, and is skipped by arrow keys and typeahead. Existing menus are unchanged. -
The message a component shows when a query matched nothing is now
emptySearchTexteverywhere, and it takes aReactNode.Selector,MultiSelector, andCommandPalettealready called itemptySearchTextand already accepted a node.Tokenizer,Typeahead,BaseTypeahead, and eachChatComposerInputtrigger called itemptySearchResultsTextand accepted only a string — so the same product could offer a "no results, create one" row in one component and not in its neighbour, and a builder who learned one had to discover the other.Nothing breaks. The type only widens, so every existing value stays valid, and
emptySearchResultsTextkeeps working exactly as released. Set both andemptySearchTextwins, with a development warning. Migration is the name alone.Deprecation lifecycle (
spec:AST-017FR28, FR31) — removal only in a later minor whose frozen manifest carries both ids of a pair: -
The layer runtime owns the viewport inset: one gutter, one cap, one fallback order, and one place an app declares a floating bar. Every anchored layer — Popover, DropdownMenu and its submenus, Typeahead, Tooltip, HoverCard, the selectors — now keeps the same gutter from each viewport edge (the spacing-4 step or the device safe-area inset, whichever is larger) and is capped to the viewport. Four components used to carry their own copies of that gutter, and they had drifted.
-
Add the first-party Markdown heading-links module.
createMarkdownHeadingLinks()is exported from@astryxdesign/core/Markdown/pluginsand gives every built-in h1–h6 a collision-safe generated fragment plus an accessible inline trailing#copy button, including headings nested in blockquotes and lists. Its frozen, versioned entry carries the namespace and safe URL base across compatible Core package copies without module-local state. The heading row usesuseContainerReveal: the button is hidden at fine-pointer rest, reveals on row hover or keyboard focus, and follows the canonical coarse/touch behavior. An unmodified tap, click, Enter, or Space copies the canonical URL without navigating, scrolling, or mutating the hash and briefly shows a check confirmation; failures stay silent. The same opaque plugin entry keeps Markdown-derived Outline aligned, supports Unicode NFKC slugs, an optional caller-owned namespace and safe permalink URL base, and leaves default Markdown plus custom heading renderers unchanged. -
Markdown: nested lists draw a different marker at each depth Bulleted lists cycle disc, circle, and square, and numbered lists cycle decimal, lower-alpha, and lower-roman, by how many lists of either kind enclose them, so each level can be told apart from the levels beside it. Numbering keeps each list's start and items.
ListandListItemkeep their public marker styles. -
Markdown plugins: read what a plugin declares, and render one plugin node as Markdown does
getMarkdownPluginCapabilities(plugin), from@astryxdesign/core/Markdown/plugins, reports whether a plugin declares syntax and whether it declares a transform, and nothing else; plugin entries stay opaque.MarkdownPluginNodeRenderer, from the new client-only@astryxdesign/core/Markdown/plugin-renderersubpath, renders one parsed extension node with the given plugins exactly asMarkdownpresents it — the plugin's renderer inside the same error boundary and suspense fallback, the same readable fallback text, and the same failure report — with no element of its own.Markdown's own output is unchanged. -
DropdownMenu takes a
triggerrender prop: hang a menu off any control.triggerrenders the control the menu opens from — an IconButton, a chip, an avatar, a list row — and hands itDropdownMenuTriggerPropsto spread: the press model, the keyboard opens, the toggle click and the ARIA wiring. The menu is named by that control througharia-labelledby.buttonandtriggerare mutually exclusive (a dev warning). -
Menu arrows wrap and PageUp/PageDown page. In
DropdownMenu,ContextMenuandDropdownMenuSubMenu, ArrowDown on the last row wraps to the first and ArrowUp on the first to the last, as macOS menus do (Selectorkeeps clamping like a native select). PageDown and PageUp move to the last and first fully visible row of a scrolling menu, and pressed there again one viewport further, never wrapping. ArrowUp on the trigger opens the menu with the last row highlighted. The key that opened the menu no longer activates the first row through its auto-repeat, and typeahead ignores a key that is part of an input-method composition.useListFocusgainshasPaging. -
DropdownMenuItem takes
href: a menu row that navigates is a real link.DropdownMenuItem(and a data-mode item) takeshref,targetandrel. The row renders as the anchor itself, withrole="menuitem", routed throughLinkProvider, so a ⌘-click, Ctrl-click or middle click keeps the browser's meaning and skipsonClick; a plain click runsonClick, closes the menu and navigates. The touch sheet renders the same item as a link row.onClicknow receives the click event. Enter and Space in every menu synthesize a click that carries the key's modifiers. -
DropdownMenu takes
menuMaxHeightto lift the 300px cap for a menu that must fit its rows; the viewport still bounds it. -
Menus and pickers act on the row under the pointer at release, and the highlight follows a held finger or mouse.
DropdownMenu,ContextMenu,DropdownMenuSubMenu,Selectorand the menu bottom sheet share one press model, the one macOS and iOS menus use: the row under the pointer when it is released is the row that acts, and the highlight follows a held pointer across the rows. A finger that lands on one row and lifts on another acts on the second — once; the click the browser aims at the first row is swallowed. A mouse released outside a menu closes it; a finger released outside leaves it open. A menu whose rows fit declarestouch-action: noneso a slide stays a slide; one that scrolls lets the browser pan it and ends the gesture. Menu rows no longer paint a pressed look where hover does not exist. New public hook:useMenuPress. -
A mouse opens a DropdownMenu on press and can drag straight into it; a finger held on the trigger opens it with the finger down. A
DropdownMenutrigger now opens its menu on a mouse press-down, and a drag from the trigger into the menu that lets go over a row picks it, as macOS menus do. The release of the opening press acts only after the pointer has entered the menu or the press has lasted about a third of a second, so a menu that opens under the pointer never picks a row nobody chose. Pressing the trigger of an open menu closes it without reopening in the same gesture. A tap still opens through its click; a finger held on the trigger for half a second opens the menu with the finger down, and a slide then picks.useMenuPressgainsonTriggerPress,triggerProps,isTriggerClickFromPressandlongPressDelayMs. -
DropdownMenuSubMenu drills in on a phone instead of opening a flyout. When a coarse pointer opened the menu, a sub-menu row replaces the menu's rows with its own and a "Back to " row, in the same box; Back, Escape or ArrowLeft return to the row. Works in compound and data mode, inside
DropdownMenuandContextMenu;presentation(flyout|drill-in|adaptive) overrides the policy. -
MultiSelectorcan offer aCreate "<query>"row for a search that matches nothing. WithhasSearch, the newhasCreateswitch puts aCreate "<query>"row first in the list when the trimmed query equals no option label under the search's own case-insensitive matching and the options have loaded. Picking it, or Enter with nothing highlighted, callsonChangewith the query appended to the value and a second argument{type: 'create', query}(exported asMultiSelectorChange), then clears the search; the caller adds an option for the new value in that same update. Every other change passes no descriptor, so existing one-argument handlers are unchanged.hasCreatewithouthasSearchwarns in development and offers nothing. Off by default. -
MultiSelectorcan hang off a control the caller renders. A newrenderTriggerrender prop renders the control the panel hangs off — a glyph in a list row, a chip, an icon button — in place of the selector's own field and button. Spread the given props onto it; the listbox is anchored to it, named bylabel, takes focus on open, and focus returns to the control on close.handleRef(open/close/toggle/isOpen, theComplexSelectorHandleshape) andonOpenChangelet the caller open the panel from a keystroke elsewhere and observe every open and close. All three are off by default; existing selectors are unchanged. -
Sub-menu flyouts stay open while the pointer travels toward them, and a press on a sub-menu row opens it without ever closing the menu. In
DropdownMenuSubMenuthe flyout now stays open while the mouse moves from the row toward the flyout inside the triangle to its near edge, and closes after the existing delay once the pointer has left both the row and that triangle, so a diagonal path to the flyout no longer folds it. A click or release on a sub-menu row opens its flyout; on an open one it confirms the flyout and moves focus into it instead of toggling it shut, as macOS sub-menu rows do.useMenuHovergainsflyoutRefand passes the leave event toonMouseLeave. -
Touch press model: under a coarse pointer the bare
:activearm is dropped and a delegated, document-level controller paints the press the way a native list does — nothing for 150 ms, then the full pressed overlay on the next frame; cancelled with no fade by 10 px of travel or by a scroll claiming the gesture, and dead until a new touch; a tap shorter than the delay paints at the lift; the release fades over 200 ms, a real fade on every surface: the pressed overlay is the pressed token at--astryx-press-alpha, a registered custom property (@property, syntax<number>) the release arm animates 1 → 0, declared once by the shared overlay styles as--_press-paintand read by whatever paints it. The controller writesdata-astryx-press="on"|"fading"on the nearest element markeddata-astryx-pressable, which every Astryx surface that paints a press now carries; a mouse keeps:active. Public API for a local pressable:usePressFeedback()from@astryxdesign/core/hooks(returns the marker to spread; installs the controller on first mount) andinteractionOverlayStylesfrom@astryxdesign/core/utils(compose one of its variants on the marked element). A press is themed through--color-overlay-pressed, which the hold, the flash and the fade all read.
-
Selector and MultiSelector announce the empty-state message they actually show, and announce it on every path that reaches one. Two defects, one cause — the live region was fed from the props instead of from what rendered:
-
Typeahead,Tokenizer, andPowerSearch(which composesTokenizer): clicking the search/combobox input after the dropdown closed without a blur now reopens it.BaseTypeaheadonly ever opened its dropdown in response to a realfocusevent. Any flow that closes the dropdown while leaving the input focused — selecting a result (which re-focuses the input internally after clearing it), pressing Escape, or a composing component (PowerSearch's token add/remove, e.g.) imperatively re-focusing the same input once it's done — dispatches no newfocusevent, sincefocus()is a no-op on an element that's already the active element. The input looked focused and clickable, but clicking it did nothing until the user clicked elsewhere first and back.BaseTypeaheadnow also opens on click, specifically when the input was already focused before the click began (checked atpointerdown, before the browser's own default action moves focus — a click that itself just caused the input to gain focus is left to the existing focus path, so the two don't double-fire a bootstrap fetch on a single first click).Only
TypeaheadandTokenizercomposeBaseTypeaheaddirectly —Selector,MultiSelector,CommandPalette, andDateTimeInputuse their own separate combobox implementations (which only followBaseTypeahead's conventions, not its code) and are unaffected by this change.Fixes #6845.
-
Card: yield to a flex row or grid track instead of widening it to the card's content. A card no longer holds its row or
1frgrid track at its min-content width, so a long unbroken value (an ID, a hash) inside a card can no longer push side-by-side cards past a phone screen. Cards that fit are unchanged. Content that cannot wrap is clipped at the card edge, as it already was for cards with an explicitwidth; truncate such values withText maxLines={1}and give wide content its own scroll region. An explicitwidthis now the card's preferred width in a row rather than a floor. To hold it, wrap the card inStackItemin a flex row, or set a consumerminWidthon the Card in Grid. -
Chat: center inline tokens on the line box using 1lh and vertical-align top, fixing vertical misalignment against adjacent text and CJK characters.
-
Prevent disabled
ClickableCardlinks from retaining an activatable destination. -
Make Code's complete public API and theme target discoverable in component documentation.
-
Keep collapsible code blocks named and recoverable when header controls disappear, honor zero-pixel height limits, and document the public root ref.
-
Expose Collapsible open, disabled, position, and divided states to themes, and document grouped state ownership and root customization.
-
Preserve
CollapsibleGroupcontext identity when a controlled string value is unchanged, avoiding unnecessary grouped-item rerenders. -
Let CommandPaletteFooter wrap translated guidance on narrow screens, correct its composition example, and add owned audit coverage.
-
Field-based inputs (TextInput, Selector, DateInput, and the rest of the input family) can now be shrunk by their row: the Field root resets its automatic minimum size, so a filter bar of a search box and selectors no longer pushes past its container on phones
-
Defer a layer
show()that arrives while another popover is mid show/hide, so a tooltip trigger regaining focus from a closing popover no longer throwsInvalidStateError. -
Markdown: read angle-bracket link destinations to their closing bracket
Markdownnow reads an angle-bracket destination as CommonMark specifies: parentheses inside the brackets are part of the address, so[a](<b(c>)links tob(c); an escaped bracket inside is part of it too, so<b\>c>isb>c; and a line ending inside the brackets makes the text no link. Unsafe schemes are refused as before. -
Markdown keeps a backslash unless it escapes punctuation, and a backslash at the end of a line is a line break
C:\Users\Adarendered asC:UsersAda: any character after a backslash swallowed it. As CommonMark specifies, a backslash now escapes only ASCII punctuation (\*,\#,\\, …); before a letter, digit, space, or other character it stays as written. A backslash at the end of a line is a hard line break. Image alt text follows the same rule. -
Markdown: cap list and blockquote nesting, so deep input cannot crash rendering
Markdownnow nests lists and blockquotes at most 100 levels deep, as it already caps emphasis; content nested deeper reads as text. A list or blockquote nested thousands of levels deep, as a crafted message can be, used to overflow the stack and throw while parsing. -
Markdown: read a block quote marker as CommonMark does
Markdownnow reads a line that starts with up to three spaces and>as a block quote, whether or not a space follows the>:>quote,> quote, and>>> nestedare quotes, as CommonMark specifies. These lines used to show as plain text with their>marks. -
Markdown: start a new list when the bullet changes
Markdownnow starts a new list when a bullet list's marker changes —- athen* bare two lists — as CommonMark specifies, and as ordered lists already did when their delimiter changes. -
Markdown shows character references such as
&,©, and©as the characters they nameFish & chips © 2026rendered with the references spelled out. Named references (every name in the HTML standard) and decimal or hexadecimal numeric references in text now render as their characters, as CommonMark specifies; inside inline code and code blocks they stay exactly as written. An unknown name or a reference without its closing;stays literal, and a decoded character is never read as Markdown syntax. -
Markdown: close a code span only at a backtick string of the same length
Markdownnow ends a code span at the next run of exactly as many backticks as opened it, never at part of a longer run, and reads runs of any length, as CommonMark specifies.`onetwo`` is one code span holding`` `, and four or more backticks open and close spans too. A run with no closer of its length stays text. -
Markdown makes a hard line break from two spaces or a backslash before a Windows (CRLF) line ending Documents saved with CRLF line endings lost their hard line breaks: the carriage return sat between the trailing spaces or backslash and the line feed, so neither was recognized and the lines ran together. Both now break the line exactly as they do in an LF document, in paragraphs, links, and block quotes and while streaming; code spans, code blocks, and table cells are unchanged.
-
Markdown: read a code fence's language after spaces
Markdownnow reads a fenced code block's language as the first word of its info string after any spaces, as CommonMark specifies, so~~~ jsand``` jsare JavaScript blocks rather than blocks with no language. Fences written without a space read as before. -
Markdown: give an image the plain text of its description as alt text
Markdownnow reads an image's description as inline content and uses its plain text as the alt text, as CommonMark specifies, so![`a]b` *c*](u)has the alta]b crather than the raw source with its backticks and asterisks. -
Markdown image alt text shows character references and escapes as the characters they name
gave the image the alt textFish & chips, so a screen reader announced "amp". Alt text now resolves character references and backslash escapes the same way body text does, for inline, standalone, and reference-style images; an escaped&and unknown names stay literal. -
Markdown: read an ATX heading indented up to three spaces as a heading
Markdownnow reads a heading line indented by up to three spaces, such as# Title, as a heading, as CommonMark specifies. Such lines used to show as plain text with their#marks, except at the very start of a streamed message. -
Markdown: read a code fence indented up to three spaces as CommonMark does
Markdownnow reads a code fence indented by up to three spaces as a code block, and a closing fence may be indented the same way, as CommonMark specifies. Each code line loses as much indentation as the opening fence has. A closing fence has only spaces or tabs after it, so a line such as```jsinside an open block stays part of the code. Such fences used to show as raw backticks or tildes in a paragraph, and an indented closing fence left the block open to the end of the document. -
Markdown: show a link whose destination opens with
<but is no angle-bracket destination as textMarkdownnow shows[a](<b>c>),[a](<b), and[link](<foo\>)as text, as CommonMark specifies: a destination that opens with<must be one whole angle-bracket destination, with no line ending inside, even after a backslash. Such links used to fall back to a link to the whole text between the parentheses. -
Markdown: keep lazy continuation lines fast in deeply nested input
Markdownno longer slows to seconds on a deeply nested blockquote or list followed by a lazy continuation line, as a crafted message can be: checking whether the line continues a paragraph now reuses what the parser already read at each level, and checking a long line for a thematic break no longer copies it. Lists and blockquotes nest at most exactly 100 levels deep. -
Markdown: find link destinations in linear time
Markdownno longer searches the rest of the text for every link or image whose destination never closes, which made a message with many of them take seconds to render. Each parenthesis now pairs once per text, so such input renders in milliseconds; links read as before. -
Markdown: decode character references and backslash escapes in link destinations, and close link text at an unescaped bracket A link or image destination now reads as CommonMark specifies:
[x](https://a.com/?a=1&b=2)links tohttps://a.com/?a=1&b=2,[x](a\)b)links toa)b, and reference definitions decode the same way. The URL safety check runs on the decoded destination, so an encoded unsafe scheme such asjavascript:is refused like the plain one. Link text and image alternative text close at the first unescaped], so[a\]b](u)is a link with the texta]b. -
Markdown: pair link text brackets as CommonMark does
Markdownnow pairs the brackets of link text as CommonMark specifies: link text may hold balanced brackets, so[a [b] c](u)is one link; the innermost bracket makes the link, so[a [b](u)links onlyb; and a link inside link text wins, so[a [b](u) c](v)shows the outer brackets as text instead of nesting links. -
Markdown: a code span in link text hides its brackets
Markdownno longer ends link text at a]inside a code span, since code spans bind tighter than links (CommonMark).[`a]b`](/u)links the codea]b, and[`[x](javascript:y)`](/rel)links the code[x](javascript:y)to/relrather than reading a link inside the code. -
Markdown links and images go to their destination when the source also gives them a title
[notes](https://example.com/notes "Release notes")linked tohttps://example.com/notes "Release notes"— an address that does not exist — and a titled image pointed at a source that could not load. A title after the destination, in double quotes, single quotes, or parentheses, is no longer part of the link or image address, and a destination in angle brackets may contain spaces. Content in any other shape keeps its meaning. -
Markdown: keep content indented into a list item in the item after a blank line
Markdownnow keeps lines indented to a list item's content in that item after a blank line, as CommonMark specifies: a nested list, a fenced code block, or another paragraph under a numbered step stays in the step, and the numbering continues after it. Such content used to end the list, so the sub-items showed as a separate list and a step's code block showed as raw text. -
Markdown: a list that mixes task and plain items shows each task item's checkbox In a list such as
- [x] Done,- Plain,- [ ] Open, each task item now shows its own read-only checkbox, checked or open and named by its text, where its marker would be, and each plain item keeps its marker; the list stays one list. Before, the task items lost their checked state and showed bullets. Lists of only task items are unchanged. -
Markdown: pair emphasis and strong markers by CommonMark's rules, so strong inside emphasis keeps its strong Runs of
*and_now pair as CommonMark specifies: by which side of a word they touch, by the nearest compatible opener, and by the rule of three.*see **bold** more*and*see **bold***render the bold inside the emphasis,**bold *both***renders the emphasis inside the strong,__foo, __bar__, baz__nests, and an escaped\*inside emphasis stays literal. Before, the first matching marker closed emphasis early and left stray*or_in the text.***text***still renders as strong around emphasis. Streaming closes an unfinished**boldbefore trailing spaces, so the partial text keeps its formatting. -
Markdown: keep the indentation of a message's first line
Markdownnow keeps the indentation of a message's first line, as it already did for every later line: two bullets indented by the same amount stay side by side, an indented numbered list keeps each item, and an indented table keeps its columns. A message that started with indented content used to render it differently from the same text after its first line. -
Markdown: end a list at a thematic break
Markdownnow reads a line such as* * *or- - -after a list item as a thematic break that ends the list, as CommonMark specifies, rather than as another item holding a nested list. -
Markdown: check a line's trailing spaces in linear time
Markdownno longer slows to seconds on a line holding a long run of spaces before its last word, as a crafted message can: deciding whether trailing spaces make a hard line break now counts them from the end of the line instead of matching a pattern that retried from every space. Line breaks read as before. -
A DropdownMenu returns focus to its trigger after a pointer dismissal, without painting a focus ring.
DropdownMenuused to blur its trigger after a pointer pick or an outside press, dropping focus to the page so the next arrow key went nowhere. Focus now returns to the trigger with the focus ring suppressed after pointer input, as the bottom-sheet presentation already did, and stays visible after a keyboard pick. A press outside that landed on a focusable control keeps focus there. -
A nav or menu trigger disabled while a hover is in flight no longer opens its surface. Hover intent schedules an open after a short delay. Disabling the trigger in that window left the scheduled open to land anyway, on a surface whose handlers were already inert — so it opened and nothing could dismiss it. The pending intent is now abandoned when the integration is disabled.
-
A Layout nested in AppShell content, or in any other Layout, no longer inherits the outer Layout's
padding. Its header, panels, content, and footer keep their default inset (or the enclosing Card, Section, or Dialog padding) instead of rendering flush against the content edge. An explicitpaddingon the nested Layout still wins. -
Restore Outline's visible keyboard focus indicator.
-
Refresh stale cached field entries when
PowerSearchreopens an already-focused input after its search source changes (#6845). -
Preserve consumer className on ToggleButton while retaining its theme classes.
-
Navigation URL safety: refuse a data URL with spaces before its media type The shared URL safety check now ignores spaces after a URL's scheme before it compares the scheme, as a data URL's media type does, so
data: text/html,…is refused likedata:text/html,…. In Markdown this also refuses links, images, and angle autolinks whose destination decodes to that form, such asdata: text/html,…. Accepted URLs are returned as before. -
Let chat follow reach the bottom when browsers round scroll offsets.
-
Toolbar's center slot no longer clips its content, so focus rings, box-shadows, and the selected-tab indicator of a TabList in
centerContentare drawn in full. Center content that cannot shrink and is wider than the space between the start and end slots now overflows it instead of being cut off. -
Forward accepted DOM props such as
id,data-*, andonClickto the Typeahead and Tokenizer root elements. Preserve existing ref, styling, anddata-testidtargets and Typeahead's built-in focus and edit behavior inside InputGroup.
-
emptyTextandemptySearchTextaccept aReactNode, but the region spoke the value only when it was a string and announced the built-in default otherwise. A product that put a link or a "create one" row in the dead end showed one message and announced another, so the screen-reader user was told something the sighted user was not reading. -
An empty result that arrived after the keystroke — an async load landing with nothing that matches an active query — was never announced at all. The message sat on screen and the region stayed silent.
Both components now read the rendered message out of the DOM and announce that, from one place that watches the panel's state rather than the keystroke. An element is announced as written, text a child component generates is announced correctly, and anything marked
aria-hiddenis left out of the announcement exactly as it is left out of the screen. A loading panel still announces nothing. -
deprecation
DEP-0001/ cleanupCLN-0001—Tokenizer.emptySearchResultsText -
deprecation
DEP-0002/ cleanupCLN-0002—Typeahead.emptySearchResultsText -
deprecation
DEP-0003/ cleanupCLN-0003—BaseTypeahead.emptySearchResultsText -
deprecation
DEP-0004/ cleanupCLN-0004—ChatComposerTrigger.emptySearchResultsText -
An explicit
widthonPopoverandmenuWidthonDropdownMenuorTypeaheadrender at their size up to the viewport. They used to be capped to the room beside the trigger, so a 352px menu opened from a control near a panel edge rendered 274px wide. -
A layer that does not fit beside its trigger flips; one that fits on neither side keeps its size and slides into view while its trigger is on screen. Once the trigger has left the viewport the layer holds its position and size instead of chasing the edge.
-
An app that floats a persistent bar over a viewport edge — a phone navigation bar — declares it once, as
inseton theLayerProviderit already mounts:<LayerProvider inset={{blockEnd: 56}}>. Every anchored layer then ends above the bar, and the toast viewport rises by the same amount, so one bar is declared once for both. Every edge defaults to zero, so nothing moves by default; an existingtoast.insetkeeps its meaning as the toast-only override.One additive prop (
LayerProvider.inset, typeLayerInset); no other prop, type, or default changes.spec:AST-059holds the decisions; theCore/Layerstories show each behavior.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry. -
Templates declare their
keywords, andbuildtells a part of a page from a page by the components the project can use (#6805) -
buildchooses where to start with a checked-in table of word weights blended with the page ranker -
astryx docs <route> --depth <levels>reads as far down the docs tree as you ask, from one doc to everything below it.--depth 0reads only the namespace you name,--depth 1adds the docs right below it (what a read without--depthshows), and--depth allgoes to the bottom. With--depth,--detailsets how much of each doc below shows:brief(the default) is one line each, named by where it sits so you can open it,compactadds its sections, andfullprints it whole. Soastryx docs cli --depth allis a map of every CLI doc, andastryx docs cli/integrations --depth all --detail fullprints the integration guides as one read. Where a read stops, a namespace says how many docs sit below it.--jsonreturns the same tree asdocs.node: each child carries its ownslotswhile the read goes deeper,childCountwhere it stops, and its text atcompactorfull.docs()takes the samedepthanddetailoptions. Reads without--depthare unchanged. -
Point at
discoverwhere people look for things to add Nothing an agent reads nameddiscover, so agents asked to find a theme searched the package registry instead. The agent blockastryx initwrites now listsdiscover <words>(integrations you could add, and the ones you have),theme listends withMore themes in packages you could add: astryx discover theme, and a text search ends withMore in packages you could add: astryx discover <query>(except--type hook, since no integration adds hooks). JSON output is unchanged. -
integration add theme --from <base>forks an existing theme as the starting point instead of a blank scaffold. The new theme copies the base's source files — renamed and rewritten for the new slug — with no link back. Use--fromwhen you want to change a lot; for a small change that stays linked, useextendsindefineTheme.
-
Say when a command did nothing:
upgradereportssourcePathFound, the integration checks reportvalidated. Two commands could legitimately do nothing and produce an envelope identical to a clean success. Both now carry the fact in a field of their own response instead of only in human text.astryx upgradedefaults--pathto./src. A project laid out asapp/(or a typo) skipped every code codemod and still reported exit 0,filesChanged: 0,errors: []and "Upgrade complete". The only warning was a log line--jsonsuppresses by design.upgrade.runnow carriessourcePathFound, and the human completion line names the directory it did not find.astryx doctor integration validate|components|docs|templatesreturned{name: null, version: null, issues: []}and exit 0 when no integration manifest was found — the same shape as a validated, healthy integration. All four envelopes now carryvalidated, false only when nothing was inspected. -
astryx manifest --jsonnow takes each command's examples from its CommandDoc and its response types from the API function it wraps, so no example differs from the documented one andupgradelistsupgrade.registry, whichupgrade --registry --jsonalready emits. -
astryx template <name> <path>andastryx layout expandnow say when they replaced Astryx demo media. Thetemplate.copyandlayout.expandreceipts carrydemoMediaReplaced, the number of demo image and video references that became placeholders (one per reference, however many fixture paths its URL carries), and the text output names the file to update (whenlayout expandprints the code instead, the same line follows it as a comment, so the output is still valid TSX). Nothing about the copy itself changed. -
astryx template <name>andtemplate()now return the same source thatastryx template <name> <path>writes, and say how many Astryx demo media references they replaced. Demo images and videos that only Astryx's own previews serve are replaced the same way in both, so code copied from the printed source no longer points at media your project doesn't have.template.showgainsdemoMediaReplaced(0 when the template carried none); in text mode the count is stated on stderr so the printed source stays exact. -
A write that fails reports ERR_WRITE_FAILED instead of a raw Node errno.
astryx templateinto an unwritable directory returned{"error": "EACCES: permission denied, open '/home/you/project/readonly/x.tsx'", "code": "ERR_UNKNOWN"}, andswizzlereturned themkdirequivalent. Two things were wrong: ERR_WRITE_FAILED is already in the frozen error registry for exactly this case, and the message carried an absolute host path where every other Astryx message names its target relative to the project.Both now throw ERR_WRITE_FAILED with the errno kept (it is the part that says what to fix) and the target named relative to the project. Nothing is left half-written: a
swizzlethat fails part-way removes the files it already copied and puts back any it replaced before it reports the error, and the message names any file it could not restore. -
When
discover --availableruns without a discover source, the CLI now explains what discover sources are and where to find Astryx packages on npm, instead of the misleading message that told users to add package names they had no way to find. The basediscoverwith no integrations also gains a pointer to npm and the integrations docs. -
A package with a namespace doc or a placed guide needs
@astryxdesign/cli0.6.4, not 0.7.0. Published 0.6.4 reads an integration's docs tree: it lists the namespace and reads each guide placed in it. 0.6.3 rejects a namespace doc and hides every doc topic the package ships.integration add doc --parentwrote"@astryxdesign/cli": ">=0.7.0", a range no released CLI satisfies, andintegration verifyfailed a docs-tree package whose CLI peer started at 0.6.4.integration add doc --parentnow writes">=0.6.4", marked optional, andintegration verifyaccepts it. A template that setsreplacesorkeywordsstill needs">=0.7.0". -
gap-reportfails when a listed integration cannot load, instead of reporting a clean result. An integration whoseastryx.integrationmodule throws on import or fails validation was left out of the handler set. With no other handler, the report fell through to the built-in GitHub fallback for Core: the command exited 0 withconsent_required, printed nothing on stderr, and offered--confirm-publicto file on Core's public tracker a report the integration might have been meant to receive.The unloadable integration now records a failed delivery in its config position, with the load error and the fix in its message. Like any handler, it turns the fallback off, so the report never goes to another package's tracker. The command exits 1, and a failed or partial report now prints each failed delivery on stderr as well as in the receipt.
-
astryx integration add theme <name> --from <base>now adds the packages the copied theme files import todependencies. A fork of a bundled theme such asneutralcopies itsicons.tsx, which importslucide-react, but the package did not declare it. Soastryx theme buildon the fork failed with "Cannot find module 'lucide-react'", and an app that installed the package hit the same error.--fromnow adds each package the copied files import, at the range the bundled themes use. It leaves out Core and React, which every Astryx app already has, and anything the package already declares. -
astryx integration packwithout--checknow points only atastryx integration verify. It used to say "Pass --check to verify the integration tarball, or runastryx integration verify", which sent people to the deprecated spelling. It now says thatintegration packis nowintegration verify, and thatnpm packbuilds the tarball. The error code and exit code are unchanged, andintegration pack --checkstill runs the same check as before. -
Search: differentiate all-word matches by total quality; index themes Within the all-words tier, every candidate whose strongest token hit was a keyword scored the same (e.g. 157), regardless of how the other query words matched. A doc matching both words by keyword outranked nothing, and
search "how to use a theme"put API reference docs above the consumer theme guide.The bonus now uses the sum of ALL token scores instead of just the strongest, so a candidate matching every word by keyword outranks one matching keyword + prose. The
themedoc also gains consumer-facing keywords so it surfaces for questions like "how to use a theme" and "how to apply a theme".Themes are now a search domain: bundled and integration-provided themes appear in results with their slug, displayName, package, and the
astryx theme addcommand.--type themefilters to them. Like--type doc, it works outside an app, where an open search now covers the docs and themes. Search help, the manifest, and the API reference list the new domain and its result fields. -
Search ranks a theme's description as prose, not as keywords A word a theme shares with your query only through its description, such as
minimal,focusorcontent, now ranks the theme like any other description instead of like a declared keyword, so it no longer lands above the components, hooks and docs that declare that word. A theme still comes first for its own slug or display name:astryx search neutralfinds the Neutral theme first. -
A package that ships a theme or a doc section
idneeds@astryxdesign/cli0.6.4, not 0.7.0. Published 0.6.4 reads typed theme descriptors and section ids; 0.6.3 rejects both and hides the package's themes or doc topics. The 0.6.5 notes said a stable CLI before 0.7.0 rejects them, sointegration add themewrote"@astryxdesign/cli": ">=0.7.0", a range no released CLI satisfies, andintegration verifyfailed a theme or section-id package whose CLI peer started at 0.6.4.integration add themenow writes">=0.6.4", marked optional, andintegration verifyaccepts it for themes and section ids. A template that setsreplacesorkeywordsstill needs">=0.7.0". -
theme buildresolves real icon imports from the selected theme instead of matching comment or string contents. Generated modules preserve named, aliased, default, and namespace registry imports, plus inherited icons with child overrides. Normal builds and--checkreject unsupported inline registries withERR_THEME_INVALIDbefore generating or writing output. Move such a registry into its own module and import it into the theme file. -
astryx theme buildin an app uses the app's installed@astryxdesign/core, and says to install Core when there is none. Run one-off withnpx @astryxdesign/cli, it failed with "Build @astryxdesign/core first (e.g.pnpm -F @astryxdesign/core build)" even when the app had Core installed, because it looked for Core only next to the CLI. It now generates with the Core the project installed, the same Core the app's<Theme>runs on. In an app without Core, the error now says to install it (npm install @astryxdesign/core). The build command stays only for the Astryx repository itself. The error code (ERR_CORE_NOT_FOUND) is unchanged.
-
TemplateDocgains an optionalkeywordslist: the ideas, domains, and other names a builder might use for what the template serves.parseTemplatevalidates it, discovery carries it from every template source,astryx searchmatches it as it matches a template's description, andastryx buildranks page templates on it. Each Core page template's closing list of ideas moved out of itsdescriptionintokeywords, so descriptions describe the layout. -
buildstarts a part of a page where it lives (spec:AST-048FR3), and the project's own components say what a part is: an idea whose head noun is a word of a component's name or keywords, Core's or an integration's, asks for a part, unless the noun names a family of page templates or the idea lists three or more pieces. A part starts from the base template of the family the idea names, else from the app shell; a change to an existing page or part (an idea whose "existing" names a page family or a component, such as "the existing table", and that does not ask for a new page) starts from the app shell. The start's reason says which case applies and why. -
A family's base template leads its family unless a variant matches two terms of its own; a base that cannot start on its own never displaces the variant that leads.
Integration templates that set
keywordsneed@astryxdesign/cli0.7.0 or later. The template metadata object is strict, so a stable CLI before 0.7.0 rejects the field, drops that template, and hides the package's doc topics; onlytemplate --listandsearchprint a warning.integration verifyfails a package whose template setskeywordsuntil it declares@astryxdesign/cli >=0.7.0, as it does forreplaces. -
api/build/kit/weights.mjsscores each candidate start (the app shell and every ready page template) from the idea's stemmed words using the tables inweights.json, and blends those scores with the ranker's own. The blend decides the start of every whole page; a part or an edit starts where it did before, and the ranker's pick of a template the tables do not list stands. Without a weights file the ranker's pick stands. The response's shape is unchanged.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry.
-
Add a shared
uploadicon, and use it for FileInput's upload affordance instead of the directionalarrowUpThemes drawuploadthroughicons.upload, separately fromarrowUp, so sort arrows and every otherarrowUpuse stay unchanged. Every bundled theme and theme template drawsuploadin its own icon style. FileInput keeps its icon size, placement, color, and accessibility in both modes; a theme with nouploadartwork shows the default upload-into-tray glyph there.A complete
IconRegistrymay still omituploadin this release. The next minor makes it required, so add anuploadentry to any registry you type asIconRegistry.
Thanks to everyone who contributed to this release:
@AstryxBot @cixzhang @Geervan @HelloOjasMutreja @imdreamrunner @jiunshinn @josephfarina @kentonquatman @korkt-kim @markselby9 @rubyycheung @thedjpetersen @vjeux
Full Changelog: https://github.com/facebook/astryx/compare/v0.6.5...v0.6.6
slate-react@0.129.0
-
#6140
7119501Thanks @dylans! - Stop dropping Android input that arrives before the editor re-renders. When the node map was stale,beforeinputevents were ignored, so the browser's native insert was overwritten by the next render. That lost the first character typed into an emptied editor, or every other character when typing fast. They now resolve against the editor's selection instead of the stale DOM. -
#6130
ab50c3bThanks @dylans! - Initialize the editor frominitialValuewhen a differenteditoris passed to an already mounted<Slate>, such as when React fast refresh re-runs theuseMemothat creates it. Previously the new editor kept emptychildren, and the next operation threw "Cannot find a descendant at path [0]".
slate@0.129.0
- #6141
1604e5fThanks @dylans! - Deleting a character or word from an empty block next to a block void now removes the empty block and selects the void, instead of deleting the void. This matches native editors. The previous behaviour deleted the image when pressing Backspace in an empty paragraph after it.
slate-dom@0.129.0
- #6009
e885f88Thanks @gbalint! - AddDOMEditor.isMounted(editor)to check whether the editor has a DOM element, and use it infocusandhasDOMNode.hasDOMNodenow returnsfalsefor an editor that is not mounted, instead of throwing.
-
#6139
b15d7dcThanks @dylans! - Keep the editor's selection whenDOMEditor.focusis called with a void, such as a mention, selected. The DOM selection is now applied after focusing the editable, because Chromium resets a caret placed inside non-editable content when focus arrives afterwards. -
#6136
96ceedbThanks @dylans! - Keep a forward DOM selection that ends inside a block void when converting it withtoSlateRange, instead of unhanging it to the end of the previous block. -
#6131
6c7c452Thanks @dylans! - Resolve drop positions inside shadow DOM.findEventRangepasses the editor's shadow root tocaretPositionFromPointwhere the browser supports it, instead of resolving to the shadow host and throwing "Cannot resolve a Slate point from DOM point". -
#6138
eb25ecdThanks @dylans! - Only readdata-slate-fragmentfrom an HTML attribute when pasting, so pasted text that happens to containdata-slate-fragment="…"no longer makes the paste fail.
v53.3.16
-
#5148 by @zbeyens – Fix DOCX export failures with quoted font names in inline styles.
-
#5145 by @vincent69001 – Fix
line-heightexport:px,pt,cmandinvalues become an absolute line height,%and unitless values a line multiplier that no longer scales with the font size.
Thanks to everyone who contributed to this release:
@vincent69001, @zbeyens
Full changelog: v53.3.15...v53.3.16