-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat: add accessibility adaptation layer #4924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: @adrcotfas/refactor/tokens_elevation
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,9 +18,12 @@ export { cornersToStyle } from './theme/tokens/sys/shape'; | |
| export { | ||
| expressiveMotion, | ||
| standardMotion, | ||
| reducedMotion, | ||
| toRawSpring, | ||
| } from './theme/tokens/sys/motion'; | ||
|
|
||
| export { useAccessibleTheme } from './theme/accessibility'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't think this belongs as a public API. We should only export what's absolutely necessary. Avoid expanding the API surface unless really needed. |
||
|
|
||
| import * as Avatar from './components/Avatar/Avatar'; | ||
| import * as Drawer from './components/Drawer/Drawer'; | ||
| import * as List from './components/List/List'; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export { useAccessibleTheme } from './useAccessibleTheme'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import * as React from 'react'; | ||
| import { AccessibilityInfo } from 'react-native'; | ||
|
|
||
| import { addEventListener } from '../../utils/addEventListener'; | ||
| import { reducedMotion } from '../tokens/sys/motion'; | ||
| import type { Theme } from '../types'; | ||
|
|
||
| function applyReducedMotion(theme: Theme): Theme { | ||
| return { | ||
| ...theme, | ||
| animation: { ...theme.animation, scale: 0 }, | ||
| motion: reducedMotion, | ||
| }; | ||
| } | ||
|
|
||
| export function useAccessibleTheme(theme: Theme, enabled = true): Theme { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this should be wrapping If this is handled, then it should be done in But also, if It probably makes sense to expose a separate prop There is also the problem of the value not being known on initial render, as it's async, so if some component has animation on render, it won't properly respect this. |
||
| const [reduceMotion, setReduceMotion] = React.useState(false); | ||
|
|
||
| React.useEffect(() => { | ||
| if (!enabled) return; | ||
|
|
||
| let cancelled = false; | ||
|
|
||
| const init = async () => { | ||
| const reduceMotion = await AccessibilityInfo.isReduceMotionEnabled?.(); | ||
| if (!cancelled && reduceMotion !== undefined) | ||
| setReduceMotion(reduceMotion); | ||
| }; | ||
|
|
||
| void init(); | ||
|
|
||
| const motionSub = addEventListener( | ||
| AccessibilityInfo, | ||
| 'reduceMotionChanged', | ||
| setReduceMotion | ||
| ); | ||
|
|
||
| return () => { | ||
| cancelled = true; | ||
| motionSub.remove(); | ||
| }; | ||
| }, [enabled]); | ||
|
|
||
| return React.useMemo(() => { | ||
| if (!enabled) return theme; | ||
| return reduceMotion ? applyReducedMotion(theme) : theme; | ||
| }, [theme, reduceMotion, enabled]); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -78,12 +78,44 @@ export const expressiveMotion: MotionConfig = { | |
| ...expressiveSpring, | ||
| easing: motionEasing, | ||
| duration: motionDuration, | ||
| prefersReducedMotion: false, | ||
| }; | ||
|
|
||
| export const standardMotion: MotionConfig = { | ||
| ...standardSpring, | ||
| easing: motionEasing, | ||
| duration: motionDuration, | ||
| prefersReducedMotion: false, | ||
| }; | ||
|
|
||
| const instantSpring = { stiffness: 10000, damping: 1 }; | ||
|
|
||
| export const reducedMotion: MotionConfig = { | ||
| spring: { | ||
| fast: { spatial: instantSpring, effects: instantSpring }, | ||
| default: { spatial: instantSpring, effects: instantSpring }, | ||
| slow: { spatial: instantSpring, effects: instantSpring }, | ||
| }, | ||
| easing: motionEasing, | ||
| prefersReducedMotion: true, | ||
| duration: { | ||
| short1: 0, | ||
| short2: 0, | ||
| short3: 0, | ||
| short4: 0, | ||
| medium1: 0, | ||
| medium2: 0, | ||
| medium3: 0, | ||
| medium4: 0, | ||
| long1: 0, | ||
| long2: 0, | ||
| long3: 0, | ||
| long4: 0, | ||
| extraLong1: 0, | ||
| extraLong2: 0, | ||
| extraLong3: 0, | ||
| extraLong4: 0, | ||
| }, | ||
| }; | ||
|
Comment on lines
+93
to
119
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure setting all of these to 0/instant animation makes sense for reduce motion. Reduce motion is about reducing motion (e.g., movement, like translation, scale, etc.). Simple animations like opacity and colors should still work. It shouldn't disable animations entirely. It probably makes more sense to handle it at the component level, because how each component changes its animation in response to this depends on the component, e.g. menu should change to simple fade instead of scale etc. |
||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,16 +7,20 @@ import type { ThemeShapes } from './shape'; | |
| import type { ThemeState } from './state'; | ||
| import type { Typescale } from './typography'; | ||
|
|
||
| /** @deprecated Will be removed in a future version. MD3 uses tonal surface colors via `theme.colors.elevation.*`. */ | ||
| type Mode = 'adaptive' | 'exact'; | ||
|
|
||
| export type ThemeBase = { | ||
| dark: boolean; | ||
| /** @deprecated Will be removed in a future version. MD3 uses tonal surface colors via `theme.colors.elevation.*`. */ | ||
| mode?: Mode; | ||
| /** @deprecated Use `theme.shapes.*` instead. Will be removed in a future version. */ | ||
| roundness: number; | ||
| /** @deprecated Use `theme.motion.*` instead. Will be removed in a future version. */ | ||
| animation: { | ||
| /** @deprecated Use `theme.motion.prefersReducedMotion` instead. Will be removed in a future version. */ | ||
| scale: number; | ||
| /** @deprecated Use `theme.motion.duration.*` instead. Will be removed in a future version. */ | ||
| /** @deprecated No-op. Use `theme.motion.duration.*` instead. Will be removed in a future version. */ | ||
| defaultAnimationDuration?: number; | ||
|
Comment on lines
+15
to
24
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove deprecated theme properties. We don't want another situation like V2/v3 themes. If necessary, the migration guide can show a helper that converts old theme to new theme for easier migration. |
||
| }; | ||
| }; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it's necessary to expose this.