Skip to content

Commit 1ef05c7

Browse files
committed
fix: updated reduce motion handling, to respeact user setting and allow overriding
1 parent 2628425 commit 1ef05c7

File tree

4 files changed

+76
-8
lines changed

4 files changed

+76
-8
lines changed

src/components/bottomSheet/BottomSheet.tsx

+45-6
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ import Animated, {
2222
useWorkletCallback,
2323
type WithSpringConfig,
2424
type WithTimingConfig,
25+
useReducedMotion,
26+
ReduceMotion,
2527
} from 'react-native-reanimated';
26-
// import BottomSheetDebugView from '../bottomSheetDebugView';
2728
import {
2829
ANIMATION_SOURCE,
2930
ANIMATION_STATE,
@@ -56,6 +57,7 @@ import {
5657
import BottomSheetBackdropContainer from '../bottomSheetBackdropContainer';
5758
import BottomSheetBackgroundContainer from '../bottomSheetBackgroundContainer';
5859
import BottomSheetContainer from '../bottomSheetContainer';
60+
// import BottomSheetDebugView from '../bottomSheetDebugView';
5961
import BottomSheetDraggableView from '../bottomSheetDraggableView';
6062
import BottomSheetFooterContainer from '../bottomSheetFooterContainer/BottomSheetFooterContainer';
6163
import BottomSheetGestureHandlersProvider from '../bottomSheetGestureHandlersProvider';
@@ -106,6 +108,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
106108
enablePanDownToClose = DEFAULT_ENABLE_PAN_DOWN_TO_CLOSE,
107109
enableDynamicSizing = DEFAULT_DYNAMIC_SIZING,
108110
overDragResistanceFactor = DEFAULT_OVER_DRAG_RESISTANCE_FACTOR,
111+
overrideReduceMotion: _providedOverrideReduceMotion,
109112

110113
// styles
111114
style: _providedStyle,
@@ -318,6 +321,13 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
318321
shouldHandleKeyboardEvents,
319322
} = useKeyboard();
320323
const animatedKeyboardHeightInContainer = useSharedValue(0);
324+
const userReduceMotionSetting = useReducedMotion();
325+
const reduceMotion = useMemo(() => {
326+
return !_providedOverrideReduceMotion ||
327+
_providedOverrideReduceMotion === ReduceMotion.System
328+
? userReduceMotionSetting
329+
: _providedOverrideReduceMotion === ReduceMotion.Always;
330+
}, [userReduceMotionSetting, _providedOverrideReduceMotion]);
321331
//#endregion
322332

323333
//#region state/dynamic variables
@@ -640,9 +650,8 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
640650
isAnimatedOnMount.value = true;
641651
}
642652

643-
isForcedClosing.value = false;
644-
645653
// reset values
654+
isForcedClosing.value = false;
646655
animatedAnimationSource.value = ANIMATION_SOURCE.NONE;
647656
animatedAnimationState.value = ANIMATION_STATE.STOPPED;
648657
animatedNextPosition.value = INITIAL_VALUE;
@@ -717,10 +726,15 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
717726
point: position,
718727
configs: configs || _providedAnimationConfigs,
719728
velocity,
729+
overrideReduceMotion: _providedOverrideReduceMotion,
720730
onComplete: animateToPositionCompleted,
721731
});
722732
},
723-
[handleOnAnimate, _providedAnimationConfigs]
733+
[
734+
handleOnAnimate,
735+
_providedAnimationConfigs,
736+
_providedOverrideReduceMotion,
737+
]
724738
);
725739
/**
726740
* Set to position without animation.
@@ -963,6 +977,16 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
963977
animatedAnimationState.value !== ANIMATION_STATE.RUNNING &&
964978
animatedCurrentIndex.value === -1
965979
) {
980+
/**
981+
* early exit if reduce motion is enabled and index is out of sync with position.
982+
*/
983+
if (
984+
reduceMotion &&
985+
animatedSnapPoints.value[animatedIndex.value] !==
986+
animatedPosition.value
987+
) {
988+
return;
989+
}
966990
setToPosition(animatedClosedPosition.value);
967991
return;
968992
}
@@ -987,7 +1011,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
9871011
animationConfigs
9881012
);
9891013
},
990-
[getEvaluatedPosition, animateToPosition, setToPosition]
1014+
[getEvaluatedPosition, animateToPosition, setToPosition, reduceMotion]
9911015
);
9921016
//#endregion
9931017

@@ -1469,12 +1493,14 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
14691493
height: animate({
14701494
point: animatedContentHeightMax.value,
14711495
configs: _providedAnimationConfigs,
1496+
overrideReduceMotion: _providedOverrideReduceMotion,
14721497
}),
14731498
};
14741499
}, [
14751500
enableDynamicSizing,
14761501
animatedContentHeight.value,
14771502
animatedContentHeightMax.value,
1503+
_providedOverrideReduceMotion,
14781504
_providedAnimationConfigs,
14791505
]);
14801506
const contentContainerStyle = useMemo(
@@ -1771,6 +1797,19 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
17711797
return;
17721798
}
17731799

1800+
/**
1801+
* exit the method if the animated index is out of sync with the
1802+
* animated position. this happened when the user enable reduce
1803+
* motion setting only.
1804+
*/
1805+
if (
1806+
reduceMotion &&
1807+
_animatedIndex === animatedCurrentIndex.value &&
1808+
animatedSnapPoints.value[_animatedIndex] !== _animatedPosition
1809+
) {
1810+
return;
1811+
}
1812+
17741813
/**
17751814
* if the index is not equal to the current index,
17761815
* than the sheet position had changed and we trigger
@@ -1811,7 +1850,7 @@ const BottomSheetComponent = forwardRef<BottomSheet, BottomSheetProps>(
18111850
runOnJS(_providedOnClose)();
18121851
}
18131852
},
1814-
[handleOnChange, _providedOnClose]
1853+
[reduceMotion, handleOnChange, _providedOnClose]
18151854
);
18161855

18171856
/**

src/components/bottomSheet/types.d.ts

+11
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { Insets, StyleProp, ViewStyle } from 'react-native';
33
import type { PanGesture } from 'react-native-gesture-handler';
44
import type {
55
AnimateStyle,
6+
ReduceMotion,
67
SharedValue,
78
WithSpringConfig,
89
WithTimingConfig,
@@ -94,6 +95,16 @@ export interface BottomSheetProps
9495
* @default true
9596
*/
9697
animateOnMount?: boolean;
98+
/**
99+
* To override the user reduce motion setting.
100+
* - `ReduceMotion.System`: if the `Reduce motion` accessibility setting is enabled on the device, disable the animation.
101+
* - `ReduceMotion.Always`: disable the animation, even if `Reduce motion` accessibility setting is not enabled.
102+
* - `ReduceMotion.Never`: enable the animation, even if `Reduce motion` accessibility setting is enabled.
103+
* @type ReduceMotion
104+
* @see https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility
105+
* @default ReduceMotion.System
106+
*/
107+
overrideReduceMotion?: ReduceMotion;
97108
//#endregion
98109

99110
//#region layout

src/utilities/animate.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
type AnimationCallback,
3-
ReduceMotion,
3+
type ReduceMotion,
44
type WithSpringConfig,
55
type WithTimingConfig,
66
withSpring,
@@ -12,13 +12,15 @@ interface AnimateParams {
1212
point: number;
1313
velocity?: number;
1414
configs?: WithSpringConfig | WithTimingConfig;
15+
overrideReduceMotion?: ReduceMotion;
1516
onComplete?: AnimationCallback;
1617
}
1718

1819
export const animate = ({
1920
point,
2021
configs,
2122
velocity = 0,
23+
overrideReduceMotion,
2224
onComplete,
2325
}: AnimateParams) => {
2426
'worklet';
@@ -30,7 +32,11 @@ export const animate = ({
3032
// Users might have an accessibility setting to reduce motion turned on.
3133
// This prevents the animation from running when presenting the sheet, which results in
3234
// the bottom sheet not even appearing so we need to override it to ensure the animation runs.
33-
configs.reduceMotion = ReduceMotion.Never;
35+
// configs.reduceMotion = ReduceMotion.Never;
36+
37+
if (overrideReduceMotion) {
38+
configs.reduceMotion = overrideReduceMotion;
39+
}
3440

3541
// detect animation type
3642
const type =

website/docs/props.md

+12
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,18 @@ This will initially mount the sheet closed and when it's mounted and calculated
109109
| ------- | ------- | -------- |
110110
| boolean | true | NO |
111111

112+
### overrideReduceMotion
113+
114+
To override the user reduce motion accessibility setting, [read more](https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility).
115+
116+
- `ReduceMotion.System`: if the `Reduce motion` accessibility setting is enabled on the device, disable the animation.
117+
- `ReduceMotion.Always`: disable the animation, even if `Reduce motion` accessibility setting is not enabled.
118+
- `ReduceMotion.Never`: enable the animation, even if `Reduce motion` accessibility setting is enabled.
119+
120+
| type | default | required |
121+
| ------- | ------- | -------- |
122+
| ReduceMotion | ReduceMotion.System | NO |
123+
112124
## Styles
113125

114126
### style

0 commit comments

Comments
 (0)