v3.7.1
- fix: escaped pseudo tokens in class names are not pseudo-elements by @tinchox5 in https://github.com/zumerlab/snapdom/pull/551
- fix(svg): export svg files without the #508 layout zoom (#552) by @j8seangel in https://github.com/zumerlab/snapdom/pull/553
- @j8seangel made their first contribution in https://github.com/zumerlab/snapdom/pull/553
Full Changelog: https://github.com/zumerlab/snapdom/compare/v3.7.0...v3.7.1
v0.17.0
- Add
PathItem#offset(distance, options), which grows, shrinks or offsets paths and compound paths with miter, round or bevel corners (#371). - Add
PathItem#outline(options), which turns the stroke of a path item into a filled path item, with its joins, caps and dashes (#371). - Add
PathItem#dash(options), which cuts a stroke into its dashes as the canvas draws them, as a group of open paths. - Add stroke profiles,
Path#strokeProfile: stops along a path that change the width, aspect and angle of the pen that draws its stroke, seeStrokeProfileStop. Not yet supported: compound paths,strokeScalingoff, andoffset(), boolean operations,interpolate()and SVG (#2505, #2506, #2507). - Add live effects,
Item#effects, which change what an item draws without changing the item, starting withoffsetandoutline.Effectdefines new ones, andItem#previewBoundsmeasures what they draw. - Add pattern colors from a
PatternDefinition, which tiles a raster or any other item, for fills and strokes, also in SVG and JSON (#829). - Add
Color#aspectfor elliptical radial gradients, and transform gradients exactly with their items, also when these scale unevenly or shear (#1744). - Add
Group#buffered, which keeps a group's drawing in a canvas until the group changes, for large groups that rarely do (#377). - Add
Item#onDrawandItem#onDrawSelection, which draw beneath an item or its selection, or replace them, also as class-level handlers such asPath.onDraw. - Add
PathItem#arcAround(center, angle)andPathItem#arcTowards(to)(#1052). - Support
optionsinPathItem#simplify(), withtoleranceand a range of segments throughfromandto, as inPathItem#smooth()(#2501). - Export and import the names and data of segments in SVG, as a
data-paper-segmentsattribute (#2398). - Add
Project#onActivateandProject#onDeactivate, also asProject.onActivateandProject.onDeactivatefor all projects. - Pass the import attributes of
import … with { … }in PaperScript on to the loader inoptions.loadofPaperScript.execute(). - Hosted projects, see
Project#host:- Share symbol and pattern definitions between items, referred to by their keys in JSON, and let scripts create new ones.
- Load the pixels of rasters from the host on first access.
- Load items in full when they move into a project with another host.
- Call
Item#onDrawandItem#onDrawSelection, throughProject#draw().
- Run the library in strict mode, which makes
Path#getNearestPoint()about 14% andItem#hitTest()about 6% faster. PaperScript still runs in sloppy mode. - Draw items with opacity, blend modes or shadows about twice as fast (#377).
- Make
PaperScope#projectan accessor, so that PaperScript'sprojectfollows the active project, asviewdoes. - Emit
deactivatewhen the active project or tool is removed. - Write the definition of symbol items to JSON as
definitioninstead ofsymbol, which still loads. - Let hosted linked text that moves into a project with another host bring a copy of its story along (#2462, #2463).
- Fix boolean operations that could lose areas or whole results, at straight curves, near-coincident crossings, curves running back and forth along a line, shallow crossings and merged vertices.
- Measure curve lengths precisely near cusps, where
Curve#getLength()andPath#getPointAt()were off by up to 6%. - Find the nearest point on curves that cover a lot of ground between their samples, in
#getNearestPoint()and the methods using it. - Fix
PathItem#smooth()with a negativetoon closed paths, which threw. - Fix
PathItem#arcTo()with tiny arcs, which missed their end point. - Keep the attributes of compound paths in
CompoundPath#reduce()when a single child is left. - Return
falsefromCompoundPath#simplify()without children. - Keep the stripes of linear gradients across them when transforming them unevenly (#1744).
- Export the gradients of items that keep their matrix to SVG in the coordinates of their elements (#2410).
- Honor the
boundsandmatrixoptions ofItem#exportSVG(). - Keep
Group#isolatedandGroup#bufferedin clones. - Keep the content of rasters when setting
Raster#size. - Load
new Raster(source)from a string where there is no document, as in workers. - Draw the segments of selected paths again by default (#1899).
- Count the duration of
Item#tween()from the first frame. - PaperScript: compile
++and--correctly wherever they appear, keep keywords apart from replaced expressions in minified code, report the right lines in stack traces on V8, and return an object fromcompile()for empty code. - Hosted projects: leave items that moved away out of
Project#takeChanges(), and turn offView#autoUpdatewhen settingProject#host. - Let Angular's esbuild builder bundle Paper.js for browsers (#2035).
v16.5.0-canary.39
- Strip internal middleware cookie headers from edge responses: #101109
- Fix stale compressed framing for forwarded fetch responses: #101108
- [use cache] Fix cache key when binary args are used: #101107
- Fix shared shell poisoning from request-supplied placeholder params: #101106
- [next/image] Fix false-positive AVIF/HEIC detection: #101105
- Fix
unstable_cacheleaking cold'use cache'fills across root params: #101104 - Fix outer 'use cache' entries reused across root param values: #101103
- Turbopack: keep CSS Modules when a loader rule's
asadds an existing extension: #101065 - Add segment config parity regression tests: #100881
- Turbopack: cleanup ReferencedAssetIdent: #101095
- [test] Fix flaky resume data cache tests: #101088
- docs: fix import.meta.glob base docs: #101085
- create-next-app: remove unused webpack bundler option: #101081
- [experiment] [turbopack-cli] compile .go files: #99980
Huge thanks to @eps1lon, @lukesandberg, @mischnic, @unstubbable, @icyJoseph, and @timneutkens for helping!
v15.5.29
This release contains security fixes for the following advisories:
v16.4.5
This release contains security fixes for the following advisories:
- Cross-tenant sensitive information disclosure in Next.js 'use cache' when called through unstable_cache
- Cache leak across root param values in nested 'use cache' functions (follow-up)
- Cache poisoning of shared fallback shells in Cache Components via request-supplied placeholder route params
- Cross-user cache disclosure and poisoning in Next.js use cache with binary arguments
- Cross-client response injection and disclosure in self-hosted Next.js applications forwarding fetched responses
- SVG rejection bypass in Next.js image optimization
- HttpOnly cookie exposure through internal response header on Next.js Edge runtime routes
Astryx v0.7.7
Astryx 0.7.7 — all @astryxdesign/* packages ship at this version.
OLD_VERSION=0.7.6 # replace with the Core version your project uses today
npm install @astryxdesign/core@0.7.7 @astryxdesign/cli@0.7.7 # plus every other @astryxdesign/* package you use, at 0.7.7
npx @astryxdesign/cli upgrade --from "$OLD_VERSION" --apply --path .
- Promote
InfoTipfrom Lab to Core, imported from@astryxdesign/core/InfoTipor the package root: an info-icon button whose press pins its help. Hover and keyboard focus preview the help, and a click, tap, Enter, or Space pins it open until Escape, a second press, a press outside, or focus leaving. Its default name is the translated "More information", and under a coarse pointer it takes taps out toward 44 px without taking a neighbour's. The@astryxdesign/labInfoTipexport is now a deprecated re-export of the Core component and is removed in the next release: import it from@astryxdesign/coreinstead.
-
AppShell keeps its header items and the end of its content inside the device's safe area on a phone page that opts into the full screen (
viewport-fit=cover). A header region or the phone top bar reaches under the status bar and out to the screen's sides while its items stay clear of the status bar, the Dynamic Island and a landscape notch. Inheight="auto", a phone top bar below a banner sticks under the top inset instead of at the top edge, so its items stay clear when the page scrolls. The main content ends clear of the home indicator (its block-end padding iscontentPaddingplus the bottom inset, so a child that fills it ends above the indicator), in the page or in the main region's own scroller. A shell with no header region or phone top bar takes no top inset, so its content keeps its own top padding there. In landscape only the header is inset, not an inline SideNav or the content's sides. Withoutviewport-fit=coverthe insets are zero and nothing moves. The AppShell docs say how a page and an installed web app opt in. -
ChatComposerInput's Return key says Send on a touch keyboard. Enter already sends the message; the editor now sets
enterkeyhint="send", so iOS shows its Send key instead of a plain Return. A newenterKeyHintprop, typed by the exported closed unionEnterKeyHint, takes another label, such asenterfor a composer whoseonKeyDownmakes Enter insert a line break on touch keyboards. -
Dialog (and so AlertDialog and CommandPalette), Drawer and MobileNav no longer blur the page behind the modal, under every pointer: the 2px full-viewport backdrop blur is costly to repaint. The dim keeps the theme's
--color-overlay, and in forced colors the modal keeps an edge so it still stands apart from the page. BottomSheet never blurred. A theme keeps the blur by settingbackdropFilter: 'blur(2px)'on the component's modal backdrop:components.dialog.base['::backdrop'],components['mobile-nav'].base['::backdrop'], and for Drawercomponents.drawer.base[':modal::backdrop'], which leaves a non-modal drawer (hasScrim={false}) unblurred. -
Under reduced motion, an indeterminate ProgressBar no longer slides: on every pointer its fill spans the whole track and gently pulses its opacity in place, from full down to 84% and back, two seconds each way. A theme's tempo does not change the pulse, and in the default light and dark themes every fill tone that stands out from the track at 3:1 still does at the pulse's lowest point.
-
Under a finger (a coarse primary pointer, on every touch device), a determinate ProgressBar moves to a new value the way iOS's progress view does: linearly, taking one second per full track of change at the theme's default tempo (0.8 s from 10% to 90%), and from wherever the fill is drawn when the value changes again mid-way. A theme's tempo scales that time. Above zero the fill never draws shorter than two track heights, and at zero it is not drawn. The motion runs on the compositor, so it keeps going while a script runs; under reduced motion, or with forced colors on, a new value lands at once. A mouse or trackpad keeps the theme's duration and easing.
-
Search fields ask a touch keyboard for its Search key and no autocorrection. The search inputs of Typeahead, Tokenizer (and so PowerSearch), CommandPaletteInput and the Selector and MultiSelector search row now carry
enterkeyhint="search"andautocorrect="off". A phone keyboard then shows a Search key instead of Return and leaves names and identifiers as typed. The key is only a label: Enter does what it did before in each field. -
SegmentedControl: under a finger, on a touch device (a coarse primary pointer), the control tracks the touch. Dragging the selected segment carries the selection along with the finger, and the segment under the finger is chosen when it lets go (
onChangefires once, at the lift); letting go outside the control selects nothing. While the selection is dragged, the selected label's colour follows it, with a margin around each boundary so a finger resting on one never flickers; label weights change only at the lift, so nothing reflows under the finger. A tap selects through the browser's own click, and a pressed segment shows the shared pressed overlay; nothing lifts or dims. A vertical drag that starts on the control still scrolls the page. A commit the item'sonClickvetoes sends the selection back at once; one a controlled parent adopts later lands without a bounce. With Reduce Motion the selection still follows the finger, with no chase, and only the lift cross-fades. Keyboard and assistive technology keep the click; no element is added. -
SegmentedControl: a mouse or a pen drags the selection as a finger does. A drag from the selected segment carries it with the pointer, and the release commits the segment under the pointer (
onChangefires once, at the release). A release outside the control selects nothing, and a drag that starts on another segment commits where it lifts. Under a mouse or a pen, every change slides the selection on the theme's duration and easing, not UIKit's spring, and a click slides it too. With Reduce Motion, a mouse's or a pen's drag still carries the selection, and its release lands at once. Keyboard and assistive technology keep the click. -
SegmentedControl: under a finger the selection slides to the new segment on UIKit's spring, whether a tap, an arrow key or a new
valuemoved it. The selection indicator is the control's own pseudo-element, so no element is added. The motion runs on the compositor and keeps moving while the main thread is busy. With Reduce Motion nothing travels or scales: the old selection fades out where it is as the new one fades in. The spring is UIKit's measured one, an internal motion role no theme retunes, and no theme value lengthens the Reduce Motion fade. With a mouse or a pen it slides on the theme's duration and easing instead. -
Switch's press and drag work with a mouse and a pen as well as a finger: a drag past the flip point toggles the switch at the release, unless the pointer came back past where it pressed. A mouse or pen press released away from the switch leaves it alone, flipped or not, as a checkbox does. With a mouse the switch keeps its desktop look, and the value moves the thumb. On a touchscreen laptop a finger flips it by the same rule, with the desktop look.
-
Under a finger, on every touch screen, Switch moves like the iOS switch. A press lifts the thumb a little, with a soft shadow, and a horizontal drag moves it with the finger and flips the switch once the finger has travelled most of the track; lifting the finger commits. A tap toggles through the browser's own click, and a hold or a short drag toggles at the lift. The thumb stays inside the track however far the finger drags past either end, in either writing direction. A press slid off the switch and lifted outside still toggles it, as on iOS. A vertical drag scrolls the page and the switch lets go. The motion runs on the compositor, so it stays smooth while scripts run. The thumb keeps its circle and its size on every device, and under a coarse pointer the switch's invisible hit area grows toward 44 × 44 px with nothing visible added, stopping halfway to any neighbouring control so a tap goes to the nearer one. The track keeps its theme's fill, and the colour change crossfades over it. With reduced motion on, a change cross-fades instead of moving on a touch screen and is immediate with a mouse. A press shows the pressed overlay, through a drag too, and a still hold selects no text. Keyboard and assistive technology behave as before. In Chromium, a Switch retargeted right after a tap, such as one tapped again mid-travel, turns around from where it is, with no step back to the start of its travel. Switch joins Slider on the shared press tracking and touch negotiation.
-
A
Dialogwithpurpose="info", aDrawer's scrim, andCommandPalettenow close on a backdrop press only when the press both starts and ends on the backdrop. Selecting text in a field and releasing past the edge no longer closes it and loses the input. A press on the backdrop alone still closes it, with a mouse, a pen, or a finger. -
BottomSheet: in WebKit, including iOS Safari, a sheet at a set height whose content sits directly in it keeps its bottom padding at the end of its scroll (0 → 16 px), instead of ending flush with the last line.
-
BottomSheet: the open sheet's dialog places its panel with a flex row instead of a grid. In desktop WebKit, measured in Playwright, an update inside an open sheet lays out faster; the iOS simulator showed no difference. A percentage
height(for example'50%') now takes that share of the screen at the bottom edge; before, a short sheet was cut short and a long one hung from the top of the screen. -
BottomSheet: a sheet closed from a control inside it, such as a Done button, a Selector's search field or a menu row, marked itself
inertandaria-hiddenwhile that control still had focus. The browser then dropped focus to the page, or screen readers were left in a hidden subtree, for the length of the exit. Now a standalone sheet that closes with focus inside it stays out ofinertandaria-hiddenwhile that focus stays, and ignores pointer and keyboard activation during its exit; when the exit ends, it closes and returns focus to its opener. The exit still plays. A sheet that closes with focus elsewhere, or that focus leaves during the exit, goes inert at once, as before. -
BottomSheet: a sheet that a Suspense boundary hid while it was closing, and then showed again, never finished closing. Its dialog stayed open, modal and inert, so the whole page under it ignored taps, clicks and focus until a reload. This happens, for example, when a sheet's action navigates to a route that suspends. Now the sheet finishes closing when it is shown again, and the page is usable.
-
A
BreadcrumbItemlink or button inside the AppShell mobile drawer now closes the drawer after it runsonClick, like theTopNavItemandSideNavItemrows beside it. Before, a crumb navigated and left the drawer open over the new page. A crumb markedisCurrent, which goes nowhere, leaves the drawer open. (#9465) -
Button, IconButton: a tooltip that repeated the button's accessible name was also added as its description, so screen readers read the same words twice ("Close, button, Close"). Astryx's own close, pagination, copy and collapse buttons did this by default. Now a tooltip whose trimmed text equals the accessible name still shows, but adds no description, when Button can read that name: its
aria-label, or its label when any icon or end content is a decorative Icon. A tooltip that says more, or a Button named another way (aria-labelledby, or text in its icon or end content), keeps the description. -
A
CheckboxListwith an errorstatusnow makes every checkboxaria-invalid, so a screen reader announces the list as invalid as each checkbox takes focus, asSwitchand the text inputs already do. The message still renders once, from the list. -
After a gesture takes a touch, the page no longer sees that touch's late
mousedownandmouseup. WebKit sends them a few milliseconds after a held tap's cancelledtouchend, aimed at whatever is under the finger by then; they now go with the click. -
Avatar, BreadcrumbItem, Button, Lightbox, SegmentedControlItem, Tab, Tokenizer: a slot whose value is
0showed a stray "0" beside its slot, or, in SegmentedControlItem's and Tab's icons and Tab's end content, was dropped. That coversstartIcon,icon,endContent, a LightboxcaptionandselectedIcon. Now each slot follows the shared presence check. Empty values (null,false,'') render no slot, as an omitted one does, and0renders inside its slot as content. A Tab whoseselectedIconis0shows it while selected instead of falling back toicon. An Avatar whosestatusis0no longer shows a stray "0"; its status slot still renders only for a truthy value. -
Pressing Enter in the typable date field of a
DateInputorDateTimeInput(the pointer surface) now submits the surrounding form when nothing is typed, as in any text field. Typed text is still committed first, and that Enter does not submit. A disabled or busy field still does nothing on Enter. -
DateRangeInput: with
presets, the popover overflowed a phone-width screen. The calendar was cut off on the right, so the Saturday column and the end of a selected range were hidden, and on screens under about 364 px Next month was out of reach too. Now, when the presets and a one-month calendar do not fit side by side, the presets stack above the calendar, and the calendar and its navigation stay inside the popover. On a short screen the popover's content scrolls. Where the presets fit beside a one-month calendar, the layout does not change. -
Dialog(andAlertDialog,CommandPalette): a dialog that unmounts while it is open, for example one rendered only while open ({isEditing && <Dialog isOpen …>}) or removed with the rest of a view, now returns focus to the control that opened it instead of dropping it to the page. -
Opening a
Drawerwithout its scrim from the keyboard no longer throws anInvalidStateErrorwhen its first control has a tooltip, such as aDrawerHeaderclose button. The tooltip now opens once the drawer is shown. -
A toast shown while a modal
Draweris open now appears inside the drawer, above it, and can be pressed and reached with Tab, as it already does over aDialogor aBottomSheet. Before, the toast stayed outside the drawer's modal dialog: it was inert there (a press on Undo did nothing, and Tab never reached it), and a wide drawer hid it completely. Toasts go back to the page as the drawer starts to close. A drawer without a scrim is unchanged. -
A toast shown before a
Drawerwithout its scrim (hasScrim={false}) opens now stays above the drawer, as it already does above a scrimlessBottomSheet. Before, the drawer painted over it, so where the drawer covered the toast's corner its action could not be seen or pressed. -
A data-mode
DropdownMenuthat opens as a bottom sheet from arenderTriggernow titles the sheet, and names its dialog, after the menu'saria-label, else the trigger's own name, as its popover does. It no longer reads "Menu" for every such sheet. (#9525) -
A window blur during a pen's press, or during a press by a finger read from its pointer events, now ends it with nothing acting at the later lift, on every surface: a
Switchno longer toggles at that pen's click. Where fingers come from pointer events, a second finger leaves both to the page's pinch even when the first rests on plain page. A disabled recognizer brings no blocking listener. -
With Reduce Motion on, a layer that opens under a finger fades in over 200 ms on easeInOut, the motion foundation's Reduce Motion values, instead of the theme's fast duration and curve. Under a mouse it still appears at once.
-
A
Linkrendered as a button (withonClickand nohref) lines up its wrapped text like the text around it, as anhrefLink does, instead of centring its second and later lines. -
A disabled
CheckboxListorRadioListnow setsaria-disabled="true"on its group, so a screen reader announces the group itself as unavailable, not only each option, and the dimmed group label counts as the label of an inactive control. -
A finger's tap that a DropdownMenu (or any menu on the press model) tracks now cancels that touch's
touchend, on every device, so the browser sends no click and no compatibility mouse events for it. Before, a busy main thread could hold that click past the 400 ms click guard window. After a tap that drilled into a sub-menu, the late click picked the sub-menu row that had come under the finger and closed the menu. A mouse or pen release keeps the 400 ms window. -
With Reduce Motion on (
design:reduced-motion), the month arrows in the DateInput and DateTimeInput bottom-sheet calendars, Reset, and a keyboard move into another month no longer scroll the months: on a computer with a mouse or trackpad the month changes at once, and on a touch screen it changes through a short opacity dip. A second step during the dip replaces the first, and unmounting the calendar during the dip scrolls nothing. -
Every
Outlinelink is now in the normal Tab order, and Tab moves from link to link, as the Outline record says. Before, the outline was one Tab stop on the current heading, with arrow, Home and End keys moving between links, so a keyboard user who did not know those keys reached only one link. The arrow, Home and End keys no longer move focus between links. (#9001) -
PopoverandusePopover: in the anchored presentation, initial focus now lands within the tap or click that opens the popover, so on iOS a text or number field in it raises the on-screen keyboard at once. Focus thatonShowmoves inside the popover is no longer pulled back to the first control. -
PowerSearch: Clear all keeps read-only filters. It removes only the filters the user can edit, the clear button shows only while an editable filter exists, Backspace on an empty input no longer removes a read-only filter, and Clear all announces "Editable filters removed" while a read-only filter remains. For callers, Clear all now callsonChangewith the read-only filters andremoveat the first removed index (0when no filter is read-only) instead of[]at the last filter's index. -
PowerSearch: in a read-only field (isReadOnly), Backspace on an empty input no longer removes the last filter. A read-only field now removes no filter, as itsisReadOnlydocs promise. -
PowerSearch: in the popover presentation, a built-in filter token's button was named by its field and operator only ("Status: is") and gave no sign that it opens an editor. Two filters on one field sounded the same, and the visible value was missing from the name. Now the token is named by all its visible text ("Status: is Open"), has
aria-haspopup="dialog"andaria-expanded, and opens an editor that is a dialog of the same name. Its remove button is "Remove Status: is Open". Token:aria-haspopupandaria-expandednow reach a clickable token's inner button, besidearia-labelledbyandaria-describedby. -
Under Reduce Motion on a touch screen, a step on a DateInput, TimeInput or DateTimeInput wheel, and a month step in the touch calendar, change under their cross-fade even on a busy page. Before, the change landed on a timer at the fade's middle, and a busy page could fire it after the fade had ended, so the rows or the month moved fully visible. Now the change lands when the fade-out ends, on the fade's own timeline, and the fade-in starts only after it, so it never shows at full opacity. The month's dip now eases each half, as the wheels' does.
-
A
ResizeHandlewhoseresizableprop goes away in the middle of a drag now ends the drag as it does on unmount: it releases the page's resize cursor and text selection, and the region hears that its gesture is over. -
A Selector's option list no longer fades in when Reduce Motion is on with a mouse or trackpad; it appears at once. On a touch screen it uses the shared Reduce Motion cross-fade.
-
In an open Selector, MultiSelector, CommandPalette, DateTimeInput time list or Chat trigger menu, a key that scrolls the list (End, Home, PageDown, type-to-select) keeps the highlight where the key put it, even when the mouse is resting over the list. Before, the row that scrolled under the still pointer took the highlight. A mouse that moves or presses still takes it.
-
Slider: every pointer drags a thumb by its travel, as UISlider does. A press on a thumb no longer jumps the value to the pointer: once the pointer has moved 10 px, the value follows its further travel along the track. A finger or a pen claims the drag only along the track, so a swipe across the slider scrolls the page; a mouse claims in any direction. On a touch screen each thumb takes a finger or a pen through a 48 px target, capped at half the gap to a range's other thumb, and the held thumb lifts. After a finger's flick the thumb coasts on UISlider's measured spring for about 0.6 s,
onChangefiring through the coast, andonChangeEndreports the value once it settles; a slow drag, a mouse drag and a pen drag end at the release. A tap on the track sets the value when the finger lifts, and a mouse click where it lands; a right click and a macOS ctrl-click change nothing. Under reduced motion the thumb does not lift and a tap's value applies at once. -
Toast: a toast raised while the window is in the background now starts with its auto-hide timer paused, so it can no longer disappear before the user returns to the tab. -
A removable
Tokenthat its width cuts off now keeps its 16 by 16 remove button. The button used to shrink to 12 px wide, so its focus ring drew as an oval and its press target narrowed to 20 by 24 px. Only the label is cut now. (#9599) -
Tooltip, HoverCard: a tap-opened tooltip or hover card whose trigger renders in another document, such as an iframe, now closes on a scroll that starts outside in that document, and on a tap outside there when the trigger takes no focus.
-
Typeahead: with focus entries on, an open list whose focus entries come back empty, or fail to load (for example after the query is cleared), now closes instead of staying open and empty. A typed search with no results still shows its message. -
Typeahead: pressing Escape while editing the selected value now restores the value and moves focus to its token, instead of dropping focus to the page. With the list shown, the first Escape only hides the list. -
useMediaQueryreturns its server default where the window has nomatchMedia, as in a test DOM, instead of throwing. Components that read it, such as Slider, now render in such a DOM; SegmentedControl, which reads it from this release, keeps rendering there. -
A picker wheel that stops on a value outside the bounds now settles on the nearest value inside them. Before, it bounced back to the value it started from. This applies to the wheels in the TimeInput, DateTimeInput and DateInput bottom sheets. For example, with
min="09:00", dragging the hour wheel from 10 to 7 settles on 9, as the iOS time picker does. A stop on a value inside the bounds is unchanged. Opening a sheet on a value outside the bounds commits nothing. When a bound changes a wheel's value while the sheet is open, as when the meridiem wheel turns past the maximum, that wheel turns onto the new value instead of jumping there. Under reduced motion, the wheel's own scrolls no longer glide. On a touch screen this travel, the step from an arrow key and a click on a row cross-fade, the rows landing while they are faded out; with a mouse or a trackpad they land at once, except the travel after a touch drag, which cross-fades on any screen.
-
Opening a Selector's list or moving its highlight re-renders only the options whose highlight or selection changes, not every option, so a long list opens sooner and arrow keys respond faster.
-
Opening a Selector with a long option list is faster: the list no longer restyles every option a second time on its first open to switch to its scrolling touch behavior.
-
Hook docs for
useOutlineFromMarkdown, soastryx hook useOutlineFromMarkdownandastryx searchreturn it, and auseOutlineFromMarkdown — Docs Articleexample block: a Markdown article and an Outline built from the same string through the hook, with a button that adds a section and its linked entry.Also released in
@astryxdesign/cli.
-
Internal: the touch presentations' animator carries a channel on from the screen when a rebase, a set or a retarget that starts now rebuilds it after its call's first frame came late and left the start unread. The channel leaves that call with a start of its own, dated from that frame, instead of starting its curve again; the call's other channels keep waiting for the browser's start. Not exported from the package entry point.
-
Internal: the touch presentations' animator reads a call whose first frame came late, and left its start unread, as started at that frame. A retarget or a read before the browser reports the start, of now or of a later time, continues near where the screen has it instead of from the call's first value. A rebase or set that rebuilds one channel's animation in that window reads that channel's first value until the frame that commits it, and the call's other channels keep reading from the first frame. The browser's start, once read, still decides. Not exported from the package entry point.
-
Internal: ChatMessage's avatar offset variable now has the private literal name
--_chat-avatar-offsetinstead of a hashed name, so the published stylesheet no longer declares an internal variable that looks public. The avatar's offset is unchanged. Not exported from the package entry point. (#9602) -
Internal: a mouse or pen drag that a gesture claims takes no new text selection and keeps the page's existing one, from the claim of whichever recognizer makes it (a swipe or a recognizer waiting on another's failure included), and a drag that starts on selectable text is left to the browser, which selects that text. Not exported from the package entry point.
-
Internal: a pan follows a trackpad's two-finger scroll where its owner allows it (
allowedScrollTypes: ['continuous'], UIKit'sallowedScrollTypesMask; none by default), along its own axis and after the scrollers under the pointer, and never a mouse wheel's notches, which scroll what is under the pointer; the screen-edge pan takes none; and a pinch takes a ctrl-wheel from a trackpad or a mouse (AST-094 FR43, DEC-24). A watcher pan never takes the wheel, and a wheel another handler already prevented stays the page's. Input the deltas cannot place, Shift+wheel included, reads as a mouse wheel; a trackpad scroll a pan follows keeps moving at the fingers' speed until their lift is read, ends there still moving, and the momentum never moves it. Not exported from the package entry point. -
ResizeHandle's pointer drag, keys and double-click move into one internal module, with no behavior change. -
Internal: when a main-thread stall delivers a late trackpad wheel and bunched wheels after it, a followed pan reads the fingers' speed over the late wheel's interval, so a flick no longer coasts short. The reading never passes the speed before the stall. Not exported from the package entry point.
-
Internal: a followed trackpad pan takes no speed from a wheel within 1.5 ms of the one before, so bunched wheels after a main-thread stall no longer carry it past the fingers' travel, at 60 to 500 Hz. Not exported from the package entry point.
-
Internal: the trackpad splitter reads a bunched wheel, one within 1.5 ms of the one before as a main-thread stall delivers it, as the steps it merged. During momentum a bunched wheel is not a jump, so momentum no longer restarts a followed pan, and the steps after it no longer read as a lift. Not exported from the package entry point.
-
Internal: a pager for touch presentations that pages like a UIKit paging scroll view. A horizontal pan moves the pages one to one and rubber-bands at the ends. The release picks the page with UIKit's rule and settles on UIKit's paging curve on the compositor, and a finger can catch it mid-flight. It takes every pointer: a mouse drags it as a finger does, and its pan follows a trackpad's horizontal scroll, at most one page per swipe. A mouse wheel's scroll stays the page's. Its motion values are internal constants. Not exported from the package entry point.
-
Internal: UIKit's paging values and math for touch presentations, measured on iOS 26.2: the thresholds that pick the page a release settles on, the settle that carries it there and
setContentOffset(animated:). The settle andsetContentOffset(animated:)replay the recorded frames to under half a pixel. The unused projection rule (selectPageandscroll.paging) is gone, so the measured thresholds are the one paging rule. Not exported from the package entry point. -
Internal: UISwitch's values measured on iOS 26.2 (its geometry, the springs of the thumb's lift, settle, travel and drag, the track colour, its minimum lift time and its flip distance) join the UIKit constants table as internal constants, with the rule a switch's drag follows as a pure function: the finger flips the switch once it has travelled the track width minus the thumb width from where it landed, coming back past that point flips it back, and lifting the finger commits the side shown, or toggles when nothing flipped. Not exported from the package entry point, and no theme sets them. Switch's touch presentation plays them.
- RichTextEditorToolbar: Insert link with nothing selected did not insert a link at the caret. In an empty paragraph nothing was inserted, and with the caret inside text the whole text around it was linked, while the dialog closed as if it had worked. Now, with the caret outside a link, Insert link inserts the entered URL as link text at the caret; with a non-empty selection it links the selected text, and with the caret inside a link it updates that link, as before.
- Typing in a
RichTextEditorcode block no longer re-tokenizes the whole block. In TypeScript, JavaScript, Python, and shell code, an edit inside one line re-tokenizes that line, plus at most the line above it, and replaces only the color ranges inside the text node it edited, so a keystroke in a 2,000-line block tokenizes as little code as one in a short block. Edits that open or close a string or comment across lines, and other languages, still re-tokenize the whole block. Colors are unchanged, except that a block whose text nodes are replaced by others with the same text is now recolored instead of left uncolored.
astryx discoverno longer listsInfoTipamong the components@astryxdesign/labcontributes: InfoTip is a Core component now, described byastryx component InfoTip.
- With TypeScript 5.3 or later,
validateIntegration(),integrationComponentConflicts()andintegrationCheck()from@astryxdesign/cli/api, and the commands that run them, reuse each TypeScript file a check parsed for later checks in the same process that parse it the same way, while the file is unchanged, instead of parsing it again for every check. Their results are unchanged.
-
The
usePressFeedback — Pressable Cardexample now shows a small card in real playing-card proportions, with corner indices, a full face and a patterned back, and a line under it that says what to try: press and hold to see the press, tap, click, Enter or Space to flip. Copying the example (astryx template, the docsite's Code tab and Install) still gives you only the hook on a Card (width={120},padding={1}) with one<Text>placeholder: the hint line is left out, not replaced. -
A new
useCombobox — Assign To Fieldexample block spreads the field, listbox and option props fromuseComboboxonto aTextInputand a list ofItemrows: typing filters a list of teammates, ArrowUp and ArrowDown move the active option while focus stays in the input, Enter or a press picks one, and Escape closes the list. Copy it withastryx template useComboboxHookUsage <path>. -
A new
useGridFocus — Color Swatch Gridexample block wiresuseGridFocusto a color swatch picker in rows of eight: the grid has one Tab stop, the arrow keys move focus cell to cell, Home and End jump within a row, Ctrl+Home and Ctrl+End jump to the corners. Each swatch is a button, so Enter or a click picks it. Copy it withastryx template useGridFocusHookUsage <path>. -
A new
useListFocus — Recent Filesexample block gives a list of buttons keyboard navigation fromuseListFocus: ArrowUp and ArrowDown move between rows, Home and End jump to the first and last row, focus wraps at the ends, and only one row is in the tab order. Copy it withastryx template useListFocusHookUsage <path>. -
A new
useOverflow — Editor Toolbarexample block shows the hook on its own: eight toolbar actions sit in a card you can resize, a hidden copy of the row holds every action plus theMoremenu markeddata-overflow-indicator, and the actions that do not fit move into theMoremenu with no flicker. Copy it withastryx template useOverflowHookUsage <path>.
withAstryx()builds Astryx from source under Turbopack instead of refusing to. It points each package's documented entry points at their source (Core, Lab, Charts and Rich Text), compiles that source with the settings the prebuilt stylesheets use, and keeps the app's own Turbopack rules off it. The new PostCSS plugin@astryxdesign/build/next/postcssreplaces an@astryx;rule with each source-built package's prebuilt stylesheet, compiled from that source: the same rules and selectors, in the same order, inside@layer astryx-base. To set it up, list@astryxdesign/build/next/postcssin the app's PostCSS config and put one@astryx;rule in the app's global stylesheet (optioncwd, the app root, defaults to the working directory). Under Turbopack, the webpack setup's@astryxdesign/build/postcssrefuses to run besidewithAstryx(), since its rules never match the classes Turbopack renders. In this source build, an installed Astryx package with a malformedpackage.jsonfails the build instead of being left out. The webpack setup is unchanged: it builds Core and Lab from source, and Rich Text and Charts keep their prebuilt stylesheets there.
- The prebuilt stylesheet build and the Turbopack source build share one module walk, compile and layer block, so a source build prints the prebuilt rules by construction. Every prebuilt stylesheet keeps its bytes.
Thanks to everyone who contributed to this release:
@cixzhang @duytbp @emilyhorsman @ernestt @HelloOjasMutreja @hskl18 @imdreamrunner @kyu-rong @maheshrijal @vjeux
Full Changelog: https://github.com/meta/astryx/compare/v0.7.6...v0.7.7