Skip to content

Commit a2e4c86

Browse files
feat: allow changing pressable defaults
1 parent 7563ea8 commit a2e4c86

6 files changed

Lines changed: 52 additions & 23 deletions

File tree

src/pressables/base.tsx

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
AnimatedPressableOptions,
1414
PressableContextType,
1515
} from '../provider/context';
16+
import type { PressableConfig } from '../provider/constants';
1617

1718
const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);
1819
type AnimatedPressableProps = ComponentProps<typeof AnimatedBaseButton>;
@@ -22,6 +23,7 @@ export type AnimatedPressableStyleOptions<TMetadata = unknown> = {
2223
isToggled: boolean;
2324
isSelected: boolean;
2425
metadata: TMetadata;
26+
config: PressableConfig;
2527
};
2628

2729
export type BasePressableProps<TMetadata = unknown> = {
@@ -37,7 +39,7 @@ export type BasePressableProps<TMetadata = unknown> = {
3739
* @platform web
3840
*/
3941
activateOnHover?: boolean;
40-
} & Omit<Partial<PressableContextType<'timing' | 'spring'>>, 'metadata'> &
42+
} & Omit<Partial<PressableContextType<'timing' | 'spring'>>, 'metadata' | 'config'> &
4143
Partial<
4244
Pick<
4345
AnimatedPressableProps,
@@ -81,18 +83,19 @@ const BasePressable: React.FC<BasePressableProps> = React.memo(
8183
onPressOut,
8284
animatedStyle,
8385
animationType: animationTypeProp,
84-
config: configProp,
86+
animationConfig: animationConfigProp,
8587
enabled = true,
8688
initialToggled = false,
8789
activateOnHover: activateOnHoverProp,
8890
...rest
8991
}) => {
9092
const {
9193
animationType: animationTypeProvider,
92-
config: configPropProvider,
94+
animationConfig: animationConfigProvider,
9395
globalHandlers,
9496
metadata,
9597
activateOnHover: activateOnHoverProvider,
98+
config,
9699
} = usePressablesConfig();
97100

98101
const lastTouchedPressable = useLastTouchedPressable();
@@ -107,31 +110,31 @@ const BasePressable: React.FC<BasePressableProps> = React.memo(
107110
const active = useSharedValue(false);
108111
const isToggled = useSharedValue(initialToggled);
109112

110-
const { animationType, config } = useMemo(() => {
113+
const { animationType, animationConfig } = useMemo(() => {
111114
if (animationTypeProp != null) {
112115
return {
113116
animationType: animationTypeProp,
114-
config: configProp,
117+
animationConfig: animationConfigProp,
115118
};
116119
}
117120
return {
118121
animationType: animationTypeProvider,
119-
config: configProp ?? configPropProvider,
122+
animationConfig: animationConfigProp ?? animationConfigProvider,
120123
};
121124
}, [
122125
animationTypeProp,
123126
animationTypeProvider,
124-
configProp,
125-
configPropProvider,
127+
animationConfigProp,
128+
animationConfigProvider,
126129
]);
127130

128131
const withAnimation = useMemo(() => {
129132
return animationType === 'timing' ? withTiming : withSpring;
130133
}, [animationType]);
131134

132135
const progress = useDerivedValue<number>(() => {
133-
return withAnimation(active.get() ? 1 : 0, config);
134-
}, [config, withAnimation]);
136+
return withAnimation(active.get() ? 1 : 0, animationConfig);
137+
}, [animationConfig, withAnimation]);
135138

136139
const onPressInWrapper = useCallback(() => {
137140
active.set(true);
@@ -214,6 +217,7 @@ const BasePressable: React.FC<BasePressableProps> = React.memo(
214217
isToggled: isToggled.get(),
215218
isSelected: lastTouchedPressable.get() === pressableId,
216219
metadata,
220+
config,
217221
})
218222
: {};
219223
}, [
@@ -224,6 +228,7 @@ const BasePressable: React.FC<BasePressableProps> = React.memo(
224228
lastTouchedPressable,
225229
pressableId,
226230
metadata,
231+
config,
227232
]);
228233

229234
const hoverProps = useMemo(

src/pressables/custom/opacity.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { interpolate } from 'react-native-reanimated';
22
import { createAnimatedPressable } from '../hoc';
33

4-
export const PressableOpacity = createAnimatedPressable((progress) => {
4+
export const PressableOpacity = createAnimatedPressable((progress, { config }) => {
55
'worklet';
66
return {
7-
opacity: interpolate(progress, [0, 1], [1, 0.5]),
7+
opacity: interpolate(progress, [0, 1], [1, config.activeOpacity]),
88
};
99
});

src/pressables/custom/scale.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { interpolate } from 'react-native-reanimated';
22
import { createAnimatedPressable } from '../hoc';
33

4-
export const PressableScale = createAnimatedPressable((progress) => {
4+
export const PressableScale = createAnimatedPressable((progress, { config }) => {
55
'worklet';
66
return {
77
transform: [
88
{
9-
scale: interpolate(progress, [0, 1], [1, 0.96]),
9+
scale: interpolate(progress, [0, 1], [config.maxScale, config.minScale]),
1010
},
1111
],
1212
};

src/provider/constants.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
import { Easing } from 'react-native-reanimated';
22

3-
export const DefaultConfigs = {
3+
export type PressableConfig = {
4+
activeOpacity: number;
5+
minScale: number;
6+
maxScale: number;
7+
};
8+
9+
export const DefaultAnimationConfigs = {
410
timing: { duration: 250, easing: Easing.bezier(0.25, 0.1, 0.25, 1) },
511
spring: {
612
mass: 1,
713
damping: 30,
814
stiffness: 200,
915
},
1016
} as const;
17+
18+
export const DefaultPressableConfig: PressableConfig = {
19+
activeOpacity: 0.5,
20+
minScale: 0.96,
21+
maxScale: 1,
22+
} as const;

src/provider/context.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
type WithSpringConfig,
66
type WithTimingConfig,
77
} from 'react-native-reanimated';
8-
import { DefaultConfigs } from './constants';
8+
import { DefaultAnimationConfigs, DefaultPressableConfig, type PressableConfig } from './constants';
99

1010
export type AnimationType = 'timing' | 'spring';
1111

@@ -20,7 +20,7 @@ export type PressableContextType<
2020
TMetadata = unknown,
2121
> = {
2222
animationType: T;
23-
config: T extends 'timing' ? WithTimingConfig : WithSpringConfig;
23+
animationConfig: T extends 'timing' ? WithTimingConfig : WithSpringConfig;
2424
globalHandlers?: {
2525
onPressIn?: (options: AnimatedPressableOptions) => void;
2626
onPressOut?: (options: AnimatedPressableOptions) => void;
@@ -32,14 +32,19 @@ export type PressableContextType<
3232
* @platform web
3333
*/
3434
activateOnHover?: boolean;
35+
/**
36+
* Pressable configuration values (opacity, scale, etc.)
37+
*/
38+
config: PressableConfig;
3539
};
3640

3741
export const PressablesContext = createContext<
3842
PressableContextType<AnimationType, unknown>
3943
>({
4044
animationType: 'timing',
41-
config: DefaultConfigs.timing,
45+
animationConfig: DefaultAnimationConfigs.timing,
4246
metadata: undefined,
47+
config: DefaultPressableConfig,
4348
});
4449

4550
export const PressablesGroupContext = createContext<{

src/provider/index.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
type WithTimingConfig,
66
} from 'react-native-reanimated';
77

8-
import { DefaultConfigs } from './constants';
8+
import { DefaultAnimationConfigs, DefaultPressableConfig, type PressableConfig } from './constants';
99
import {
1010
PressablesContext,
1111
PressablesGroupContext,
@@ -19,7 +19,7 @@ export type PressablesConfigProps<
1919
> = {
2020
children?: React.ReactNode;
2121
animationType?: T;
22-
config?: T extends 'timing' ? WithTimingConfig : WithSpringConfig;
22+
animationConfig?: T extends 'timing' ? WithTimingConfig : WithSpringConfig;
2323
globalHandlers?: {
2424
onPressIn?: (options: AnimatedPressableOptions) => void;
2525
onPressOut?: (options: AnimatedPressableOptions) => void;
@@ -31,6 +31,10 @@ export type PressablesConfigProps<
3131
* @platform web
3232
*/
3333
activateOnHover?: boolean;
34+
/**
35+
* Pressable configuration values (opacity, scale, etc.)
36+
*/
37+
config?: Partial<PressableConfig>;
3438
};
3539

3640
export const PressablesGroup = ({ children }: PropsWithChildren) => {
@@ -52,20 +56,22 @@ export const PressablesGroup = ({ children }: PropsWithChildren) => {
5256
export const PressablesConfig = <T extends AnimationType, TMetadata = unknown>({
5357
children,
5458
animationType = 'timing' as T,
55-
config,
59+
animationConfig,
5660
globalHandlers,
5761
metadata,
5862
activateOnHover,
63+
config,
5964
}: PressablesConfigProps<T, TMetadata>) => {
6065
const value = useMemo(() => {
6166
return {
6267
animationType,
63-
config: config ?? DefaultConfigs[animationType],
68+
animationConfig: animationConfig ?? DefaultAnimationConfigs[animationType],
6469
globalHandlers,
6570
metadata,
6671
activateOnHover,
72+
config: { ...DefaultPressableConfig, ...config },
6773
};
68-
}, [animationType, config, globalHandlers, metadata, activateOnHover]);
74+
}, [animationType, animationConfig, globalHandlers, metadata, activateOnHover, config]);
6975

7076
return (
7177
<PressablesContext.Provider value={value}>
@@ -75,3 +81,4 @@ export const PressablesConfig = <T extends AnimationType, TMetadata = unknown>({
7581
};
7682

7783
export * from './hooks';
84+
export type { PressableConfig } from './constants';

0 commit comments

Comments
 (0)