Skip to content

fix(Layer): the touch cross-fade uses the motion foundation's Reduce Motion values - #8355

Draft
vjeux wants to merge 1 commit into
meta:mainfrom
vjeux:uikit/c26-layer-rm-values
Draft

vjeux wants to merge 1 commit into
meta:mainfrom
vjeux:uikit/c26-layer-rm-values

Conversation

@vjeux

@vjeux vjeux commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Follows #8322 (merged), as its review agreed: the layer's touch cross-fade takes the motion foundation's own Reduce Motion values.

User impact

With Reduce Motion on, a layer that opens under a finger fades in over the theme's fast duration and curve (#8322), capped at 200 ms. The motion foundation's policy, which every other touch presentation follows, fades over exactly 200 ms on easeInOut. A layer and a touch presentation opened side by side fade on different clocks.

Evidence

iOS 26.2 Safari with Reduce Motion on, a tap on the Tooltip's term (a grey dot marks the finger); after this change:

After

  • It fades in where it lands, opacity only, over 200 ms on easeInOut, with no travel or scale; under a mouse it still appears at once.
  • Regression proof: the Chromium contract's four cross-fade cases (Tooltip and HoverCard, default and slow theme) check the curve and the 200 ms; they fail on main's build and pass on this one.

Problem and solution fit

layerAnimations.stylex.ts timed the cross-fade with the theme's fast duration and easing. The animator's Reduce Motion policy (design:reduced-motion) uses a fixed 200 ms easeInOut under a coarse pointer and no animation under any other pointer. The layer now uses the same values and spells its media queries as that policy does: (prefers-reduced-motion: reduce) and (pointer: coarse) and (prefers-reduced-motion: reduce) and (not (pointer: coarse)). The keys stay literal, since the StyleX build orders an imported at-rule key differently; the values become the foundation's shared constants once those are on main.

Expected behavior and authority

  • design:reduced-motion (current): on a coarse pointer an opacity-only cross-fade in 200 ms or less that no theme value lengthens (DR2, DR4); on other pointers an instant change (DR3).

Smallest restoration

Two media conditions and their values in layerAnimations.stylex.ts; the contract checks the easing, and its mouse case asserts a fine pointer in its context first.

Scope

  • One defect is restored.
  • Separable contradictory or unsettled tagalongs were removed or split.
  • No new public API, visual representation, default, or interaction model is hidden under the bug-fix label.
  • Public text and artifacts contain no internal Meta context.

Testing

  • pnpm exec playwright test packages/core/src/Layer/__tests__/LayerReducedMotion.a11y.chromium.spec.ts --project chromium after pnpm storybook:build: 8/8. The four cross-fade cases fail on main's build (theme-timed curve).
  • pnpm vitest run packages/core/src/Layer: 210 pass.
  • iOS 26.2 simulator in Safari, 60 fps recording with a page log, Reduce Motion set through the simulator's accessibility settings.
  • Core typecheck, eslint, prettier.

…Motion values

Under Reduce Motion the layer entrance now takes the values and media queries
the motion foundation's policy uses: under a coarse pointer an opacity-only
fade of 200 ms on easeInOut that no theme value lengthens
(design:reduced-motion DR2, DR4), under any other pointer no animation (DR3).
The queries are spelled as that policy spells them (literal keys, which the
StyleX build orders as written), and the values become its shared constants
once those are on main.

The Chromium contract checks the curve too: ease-in-out, which fails on the
theme-timed fade on main. Its mouse case asserts that its context is a fine
pointer before it checks anything.
@vercel

vercel Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 25, 2026 3:58am UTC

Request Review

@github-actions github-actions Bot added the needs:design-review Affects visuals — Design should review label Oct 25, 2026
@astracat-bot

astracat-bot Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
❓ Needs maintainer input (for maintainers only) Oct 30, 2026, 5:32 AM UTC

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 25, 2026

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks: the layer's Reduce Motion touch fade works as described, an opacity-only 200 ms fade under a finger, with mouse and no-preference entrances unchanged. Approval waits on one owner decision: design:reduced-motion DR2 only bounds this fade at 200 ms and names no curve, so a fixed 200 ms on easeInOut whatever the theme (the policy proposed in #8056) needs an engineering owner to provide or identify the governing spec. An engineering owner records that decision by commenting /approve-spec f23d41c0cf2f88ef38b81e60f5bd0992d191fa62 on this pull request (the author may do so if they are an engineering owner), or by stating the curve and duration in DR2.

  • If the curve stays, let the contract's ease-in-out check also accept cubic-bezier(0.42, 0, 0.58, 1): Chromium reports the curve as written, and only the production Storybook build turns it into ease-in-out.

[Automated review]

Comment on lines +103 to +106
animationTimingFunction: {
default: easeVars['--ease-standard'],
'@media (prefers-reduced-motion: reduce) and (pointer: coarse)':
'cubic-bezier(0.42, 0, 0.58, 1)',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This curve is the open question for an owner: design:reduced-motion DR2 bounds the touch cross-fade at 200 ms, opacity only, and names no curve, while main's layer fade uses the theme's --ease-standard. Whether core's reduced-motion touch cross-fade is a fixed 200 ms on easeInOut whatever the theme (the policy proposed in #8056) needs an engineering owner's decision.

Comment on lines +127 to +129
// The motion foundation's cross-fade: Core Animation's easeInOut,
// cubic-bezier(0.42, 0, 0.58, 1), which the engine names ease-in-out.
expect(entrance.easing).toBe('ease-in-out');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chromium reports this value as cubic-bezier(0.42, 0, 0.58, 1) (computed on a Storybook dev server, and the core package's dist/astryx.css ships it that way); it reads ease-in-out here only because the production Storybook build rewrites it. If the curve stays, accept both spellings and say the build, not the engine, renames it. The same applies at line 153.

@github-actions

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR

🧪 Sandbox Preview

View Sandbox for this PR

Component Size

Component Import before Import after Delta CSS before CSS after Delta
core/AlertDialog 51.2KB 51.2KB +29B 12.2KB 12.2KB -22B
core/AppShell 52.3KB 52.3KB +28B 11.4KB 11.4KB +15B
core/Avatar 34.5KB 34.5KB +33B 6.2KB 6.2KB +17B
core/AvatarGroup 36.8KB 36.8KB +27B 6.3KB 6.3KB +17B
core/AvatarGroupOverflow 36.9KB 36.9KB +30B 6.2KB 6.2KB +18B
core/Banner 44.4KB 44.4KB +30B 9.5KB 9.6KB +20B
core/BaseTypeahead 50.2KB 50.2KB +20B 9.7KB 9.7KB +18B
core/BreadcrumbItem 62.2KB 62.2KB +27B 10.8KB 10.8KB +17B
core/Button 40.0KB 40.0KB +28B 9.0KB 9.0KB +11B
core/Calendar 51.7KB 51.7KB +26B 9.8KB 9.8KB +20B
core/Carousel 45.6KB 45.6KB +23B 10.0KB 10.0KB +16B
core/ChatComposer 56.6KB 56.6KB +23B 10.5KB 10.5KB +18B
core/ChatComposerInput 52.2KB 52.2KB +29B 9.8KB 9.8KB +20B
core/ChatComposerTokenElement 52.2KB 52.2KB +27B 9.8KB 9.8KB +20B
core/ChatDictationButton 43.3KB 43.3KB +28B 9.2KB 9.3KB +17B
core/ChatLayout 45.7KB 45.7KB +24B 9.7KB 9.7KB +24B
core/ChatLayoutScrollButton 43.1KB 43.2KB +30B 9.3KB 9.4KB +20B
core/ChatMessageList 28.3KB 28.3KB +1B 7.6KB 7.6KB +12B
core/ChatSendButton 42.6KB 42.6KB +23B 9.0KB 9.0KB +12B
core/ChatToolCalls 31.7KB 31.7KB 0B 8.7KB 8.7KB +11B
core/CheckboxInput 46.4KB 46.4KB +23B 9.2KB 9.2KB +8B
core/CheckboxList 42.8KB 42.8KB +25B 7.9KB 7.9KB +10B
core/CheckboxListItem 50.5KB 50.5KB +25B 10.3KB 10.3KB +21B
core/CodeBlock 55.4KB 55.4KB +28B 10.4KB 10.5KB +26B
core/CommandPalette 48.5KB 48.5KB +1B 11.6KB 11.6KB -22B
core/CommandPaletteInput 31.7KB 31.7KB 0B 8.0KB 8.0KB +11B
core/ComplexSelector 51.9KB 51.9KB +29B 10.3KB 10.4KB +20B
core/ContextMenu 73.5KB 73.5KB +28B 14.2KB 14.2KB +15B
core/DateInput 89.4KB 89.4KB +28B 14.3KB 14.3KB +17B
core/DateRangeInput 61.1KB 61.1KB +19B 10.9KB 10.9KB +19B
core/DateTimeInput 98.6KB 98.7KB +28B 14.7KB 14.7KB +8B
core/DialogHeader 45.6KB 45.6KB +23B 9.5KB 9.5KB +19B
core/Drawer 22.6KB 22.6KB +25B 7.9KB 7.9KB +10B
core/DrawerHeader 45.5KB 45.5KB +30B 10.9KB 10.9KB +19B
core/DropdownMenu 68.5KB 68.6KB +24B 14.4KB 14.4KB +15B
core/DropdownMenuSubMenu 54.0KB 54.1KB +27B 9.3KB 9.3KB +18B
core/Field 41.1KB 41.1KB +23B 7.7KB 7.7KB +12B
core/FieldLabel 36.7KB 36.7KB +20B 6.4KB 6.4KB +17B
core/FileInput 50.5KB 50.5KB +33B 10.1KB 10.1KB +17B
core/Heading 9.0KB 9.0KB 0B 6.7KB 6.7KB +18B
core/HoverCard 14.3KB 14.3KB +26B 4.8KB 4.8KB +21B
core/IconButton 40.0KB 40.1KB +27B 9.0KB 9.0KB +11B
core/InputGroup 41.6KB 41.6KB +25B 7.8KB 7.8KB +12B
core/LayerProvider 54.3KB 54.3KB +9B 9.9KB 9.9KB +18B
core/Lightbox 46.3KB 46.3KB +33B 9.6KB 9.6KB +13B
core/Link 40.5KB 40.5KB +23B 7.4KB 7.4KB +10B
core/ListItem 49.9KB 50.0KB +29B 10.3KB 10.3KB +21B
core/Markdown 132.3KB 132.4KB +22B 16.9KB 16.9KB +27B
core/MobileNav 45.5KB 45.5KB +20B 9.8KB 9.8KB +18B
core/MobileNavToggle 43.0KB 43.0KB +24B 9.2KB 9.2KB +19B
core/MoreMenu 68.8KB 68.8KB +26B 14.4KB 14.4KB +15B
core/MultiSelector 71.3KB 71.3KB +31B 14.1KB 14.1KB +3B
core/NumberInput 52.3KB 52.4KB +27B 10.4KB 10.4KB +18B
core/Pagination 82.8KB 82.8KB +24B 14.8KB 14.8KB +18B
core/Popover 43.9KB 44.0KB +22B 9.2KB 9.2KB +20B
core/PowerSearch 143.2KB 143.2KB +37B 18.1KB 18.1KB +19B
core/ProgressBar 7.6KB 7.6KB -1B 6.4KB 6.4KB +17B
core/RadioList 42.4KB 42.4KB +31B 7.8KB 7.8KB +12B
core/RadioListItem 49.0KB 49.1KB +27B 9.4KB 9.4KB +10B
core/SegmentedControl 35.8KB 35.8KB +20B 6.2KB 6.2KB +17B
core/Selector 74.2KB 74.2KB +26B 14.5KB 14.5KB +18B
core/SideNav 52.6KB 52.6KB +24B 10.3KB 10.3KB +16B
core/SideNavCollapseButton 43.4KB 43.4KB +26B 9.2KB 9.3KB +19B
core/SideNavHeading 51.4KB 51.4KB +21B 9.9KB 9.9KB +15B
core/SideNavItem 51.1KB 51.1KB +26B 9.9KB 9.9KB +15B
core/Slider 45.4KB 45.4KB +23B 8.3KB 8.3KB +11B
core/Spinner 26.2KB 26.2KB -1B 7.4KB 7.4KB +12B
core/StatusDot 15.9KB 15.9KB +32B 6.0KB 6.0KB +18B
core/Stepper 44.2KB 44.2KB +23B 9.3KB 9.4KB +19B
core/Switch 45.2KB 45.3KB +29B 9.1KB 9.1KB +8B
core/TabMenu 48.3KB 48.3KB +27B 9.8KB 9.8KB +19B
core/Table 79.2KB 79.2KB +32B 14.6KB 14.6KB +15B
core/TableCell 74.5KB 74.6KB +29B 14.4KB 14.4KB +16B
core/TableHeaderCell 74.3KB 74.4KB +30B 14.3KB 14.4KB +15B
core/TableSelectionToolbar 49.0KB 49.0KB +24B 11.0KB 11.0KB +18B
core/Text 8.5KB 8.5KB +1B 6.7KB 6.7KB +18B
core/TextArea 45.8KB 45.8KB +22B 9.1KB 9.2KB +22B
core/TextInput 49.8KB 49.9KB +32B 10.2KB 10.2KB +18B
core/Thumbnail 46.9KB 46.9KB +29B 10.8KB 10.8KB +19B
core/TimeInput 75.9KB 75.9KB +20B 13.2KB 13.3KB +16B
core/Timer 9.1KB 9.1KB 0B 6.7KB 6.7KB +18B
core/Timestamp 27.4KB 27.4KB +1B 9.3KB 9.3KB +18B
core/Toast 51.0KB 51.0KB +9B 9.5KB 9.5KB +17B
core/ToggleButton 40.9KB 40.9KB +25B 9.1KB 9.1KB +18B
core/Tokenizer 60.6KB 60.6KB +23B 11.4KB 11.4KB +17B
core/Tooltip 14.0KB 14.0KB +24B 4.8KB 4.8KB +22B
core/TopNav 46.4KB 46.5KB +28B 10.1KB 10.1KB +16B
core/TopNavHeading 50.8KB 50.8KB +19B 9.7KB 9.7KB +18B
core/TopNavMegaMenu 50.8KB 50.8KB +25B 10.5KB 10.6KB +15B
core/TopNavMenu 50.3KB 50.3KB +28B 9.9KB 9.9KB +17B
core/Typeahead 57.2KB 57.2KB +25B 11.0KB 11.0KB +16B

Sizes are gzip. Import counts the JavaScript the import loads eagerly; CSS counts the package stylesheet rules referenced by the modules it can load from its own package, lazily loaded ones included.

Bundle Size Summary

Gzip figures measure each package's entry file, not the code an import pulls in.

Package Entry (ESM) Entry gzip before Entry gzip after Delta
@astryxdesign/core 4.9KB 1.2KB 1.2KB 0B
Package stylesheet Gzip before Gzip after Delta
@astryxdesign/core 33.7KB 33.7KB -18B

Accessibility Audit

Status: No accessibility violations detected.

Visual Regression

48 of 502 shot(s) changed.

A change here is a question, not a failure: check whether the after is the
picture you intended. Record that review on the PR. Baseline maintenance is an
explicit dispatch of CI; this report never rewrites the baseline or adds a release gate.

component story theme mode pixels
Selector Indicator Space Bottom Sheet Narrow End RTL neutral light 753,933
Selector Indicator Space Bottom Sheet Wide Start neutral light 740,072
RichTextEditor Markdown parity: side by side probe dark 556,900
RichTextEditor Markdown parity: side by side probe light 538,816
Chat Full AI Chat probe light 230,823
Chat Full AI Chat probe dark 229,805
AppShell With Mobile Nav probe light 217,010
AppShell With Mobile Nav probe dark 216,960
Collapsible Dividers probe dark 66,445
Collapsible Dividers probe light 66,445
AppShell Playground neutral dark 65,198
AppShell Playground neutral light 63,788
Chat Default neutral dark 36,304
Chat Default neutral light 35,767
Chat Empty State probe light 23,531
Chat Empty State probe dark 22,622
ChatAutoScroll Scroll Behavior Comparison neutral dark 15,378
ChatAutoScroll Scroll Behavior Comparison neutral light 14,107
Chat With Attachments probe light 13,406
Chat With Attachments probe dark 11,232

and 28 more.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

@vjeux
vjeux marked this pull request as draft October 29, 2026 22:35

This branch was successfully deployed

1 active deployment
Preview — f23d41c0 Deployed Oct 25, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant