Chore: Enable no-unreduced-motion and fix errors (#86572)

* enable `no-unreduced-motion` in betterer

* move all animation calls inside handleReducedMotion

* fix violations + enable rule

* update rule README

* remove unnecessary transition from <Collapse>

* remove handleReducedMotion utility and add handleMotion to theme

* update to use new theme value

* handle Dropdown and IconButton

* handle AppChromeMenu and update lint message

* keep rotation at a reduced speed

* handle DashboardLoading
This commit is contained in:
Ashley Harrison
2024-04-29 13:12:36 +01:00
committed by GitHub
parent 8a1f43a65d
commit c151a97110
39 changed files with 321 additions and 132 deletions

View File

@@ -24,7 +24,89 @@ Avoid direct use of `animation*` or `transition*` properties.
To account for users with motion sensitivities, these should always be wrapped in a [`prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) media query.
`@grafana/ui` exposes a `handledReducedMotion` utility function that can be used to handle this.
There is a `handleMotion` utility function exposed on the theme that can help with this.
#### Examples
```tsx
// Bad ❌
const getStyles = (theme: GrafanaTheme2) => ({
loading: css({
animationName: rotate,
animationDuration: '2s',
animationIterationCount: 'infinite',
}),
});
// Good ✅
const getStyles = (theme: GrafanaTheme2) => ({
loading: css({
[theme.transitions.handleMotion('no-preference')]: {
animationName: rotate,
animationDuration: '2s',
animationIterationCount: 'infinite',
},
[theme.transitions.handleMotion('reduce')]: {
animationName: pulse,
animationDuration: '2s',
animationIterationCount: 'infinite',
},
}),
});
// Good ✅
const getStyles = (theme: GrafanaTheme2) => ({
loading: css({
'@media (prefers-reduced-motion: no-preference)': {
animationName: rotate,
animationDuration: '2s',
animationIterationCount: 'infinite',
},
'@media (prefers-reduced-motion: reduce)': {
animationName: pulse,
animationDuration: '2s',
animationIterationCount: 'infinite',
},
}),
});
```
Note we've switched the potentially sensitive rotating animation to a less intense pulse animation when `prefers-reduced-motion` is set.
Animations that involve only non-moving properties, like opacity, color, and blurs, are unlikely to be problematic. In those cases, you still need to wrap the animation in a `prefers-reduced-motion` media query, but you can use the same animation for both cases:
```tsx
// Bad ❌
const getStyles = (theme: GrafanaTheme2) => ({
card: css({
transition: theme.transitions.create(['background-color'], {
duration: theme.transitions.duration.short,
}),
}),
});
// Good ✅
const getStyles = (theme: GrafanaTheme2) => ({
card: css({
[theme.transitions.handleMotion('no-preference', 'reduce')]: {
transition: theme.transitions.create(['background-color'], {
duration: theme.transitions.duration.short,
}),
},
}),
});
// Good ✅
const getStyles = (theme: GrafanaTheme2) => ({
card: css({
'@media (prefers-reduced-motion: no-preference), @media (prefers-reduced-motion: reduce)': {
transition: theme.transitions.create(['background-color'], {
duration: theme.transitions.duration.short,
}),
},
}),
});
```
### `theme-token-usage`

View File

@@ -55,7 +55,7 @@ const rule = createRule({
description: 'Check if animation or transition properties are used directly.',
},
messages: {
noUnreducedMotion: 'Avoid direct use of `animation*` or `transition*` properties. Use the `handleReducedMotion` utility function or wrap in a `prefers-reduced-motion` media query.',
noUnreducedMotion: 'Avoid direct use of `animation*` or `transition*` properties. Use the `handleMotion` utility function from theme.transitions or wrap in a `prefers-reduced-motion` media query.',
},
schema: [],
},