Repository navigation
fix(remix): honor reduced motion in animated components - #327
leoafarias wants to merge 2 commits into
Conversation
Add RemixReducedMotion, which reports whether MediaQuery.disableAnimations or the platform's accessibility reduceMotion is set and rebuilds when either changes. iOS Reduce Motion only sets reduceMotion, so reading MediaQuery.disableAnimations alone missed it. The select menu and accordion panel now open and close without a transition, and RemixSpinner holds a static frame. Skeleton and sidebar, which already followed MediaQuery.disableAnimations, now follow iOS Reduce Motion too. Style animations declared with .animate(...) are driven by Mix and are not affected.
Rename RemixReducedMotion to RemixReducedMotionBuilder and drop its static of. The select reads the preference through an internal function when a transition starts, and the sidebar observes accessibility changes so a platform-only change settles a collapse already under way. The builder only rebuilds when the computed preference changes. Docs state which components follow which signal, no longer promise dialog or tooltip behavior that comes from Naked UI, and describe the Mix gap. RemixSkeleton no longer throws without a MediaQuery ancestor.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2c59c79fb4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| duration: reduceMotion | ||
| ? Duration.zero | ||
| : const Duration(milliseconds: 200), |
There was a problem hiding this comment.
Restore exit animations when reduced motion is turned off
If a panel is expanded with reduced motion enabled, then the preference is turned off while the panel remains expanded, its next collapse still happens instantly. AnimatedSwitcher captures the controller duration when each child enters, so changing the widget's duration back to 200 ms does not update the existing panel's zero-duration controller. The restoration test changes the preference before expanding and therefore misses this case. Ensure existing panels regain their exit animation when reduced motion is disabled, without remounting their state.
Useful? React with 👍 / 👎.
Description
Remix components that hard-code their own motion ignored reduced motion, and
MediaQuery.disableAnimationsalone misses iOS Reduce Motion (iOS only sets the platform accessibilityreduceMotion).RemixReducedMotionBuilder. Its builder receives whether the user asked for reduced motion (MediaQuery.disableAnimationsor the platformreduceMotion) and rebuilds only when that value changes. AMediaQueryoverride can force reduced motion on but cannot turn the platformreduceMotionoff. Same definition as naked_ui's reduced-motion read in fix(naked_ui): honor reduced motion in dialogs, tooltips, disclosures, and toasts #330, so both packages agree.RemixSpinnerstops on a static frame. Widget tree and semantics are the same in both modes.RemixSkeletonandRemixSidebar, which already followedMediaQuery.disableAnimations, now also follow iOS Reduce Motion; a platform-only change settles a sidebar collapse already under way.RemixSkeletonno longer throws without aMediaQueryancestor.Landing order: land after #330 (naked_ui reduced motion); the remix release PR raises the
naked_uifloor to the release that contains it. There is no code dependency, and the docs here do not promise dialog or tooltip behavior.Conflict note: #323 (
fix/remix-sidebar-media-query) changes the same lines insidebar_widget.dart; resolve by keeping this PR's version (observer plus the internal reduced-motion read).Known gap, follow-up upstream in Mix:
.animate(...)styles, including preset recipes, are not covered. Mix never reads reduced motion andStyleBuilderoffers no interception point. A zero-duration curve asserts (TweenSequenceItemweight > 0, though 1 ms is accepted);StyleSpec.copyWithcannot clearanimation, though a freshStyleSpeccan;MixInteractionDetectorand_ExternalControllerProviderare not exported. Flutter already shortens Mix curve animations under the platformdisableAnimations; springs, iOS Reduce Motion, andMediaQueryoverrides still animate. The guide shows gating.animatewithRemixReducedMotionBuilder. The proper fix is in Mix'sStyleAnimationBuilder(btwld/mix#1070 was closed unmerged).Validation
reduceMotion, live change both ways, no rebuild on unrelated accessibility changes, the one-wayMediaQueryoverride, observer removal), select, accordion, and spinner, plus sidebar (including a platform-only flip mid-collapse) and skeleton (platform cases, noMediaQueryancestor). 17 tests fail on the unchanged components; the rebuild-on-change, sidebar mid-transition, and skeleton tests fail with their fix reverted.flutter testin packages/remix (2864) and registry_source (1390),dart analyze, rootdart format,melos run ci:checks,melos run docs:check.Related Issues
btwld/mix#1070 (closed) for the Mix gap. Supersedes the closed #258 for the Remix components.
Checklist
///).Breaking Change