Files
calendar/companion/components/AppPressable.tsx
T
Dhairyashil ShindeandGitHub 9203cb262c feat(companion): component improvements, migrate to path aliases, expo-haptics, expo-image (#26226)
* react compiler

* remove compilation mode 'all', it will use infer by default

* feat(companion): add theme tokens, path aliases, and component improvements

- Extend tailwind.config.js with Cal.com brand color tokens (cal.text, cal.bg, cal.border, cal.accent, cal.brand)
- Create theme/colors.ts for JS usage where Tailwind classes can't be used
- Configure path aliases in tsconfig.json (@/components, @/hooks, @/utils, etc.)
- Add expo-image and expo-haptics dependencies
- Enhance AppPressable with Reanimated animations (opacity + scale) and haptic feedback
- Extract shared logic from BookingListItem into useBookingListItemData hook and BookingListItemParts
- Extract shared logic from EventTypeListItem into useEventTypeListItemData hook and EventTypeListItemParts
- Extract shared logic from AvailabilityListItem into AvailabilityListItemParts
- Update all list item components to use new theme tokens instead of hardcoded hex values

* fix react compiler non memo issue

* feat(companion): migrate to path aliases and expo-image

- Remove theme/colors.ts and theme/index.ts (defer dark mode to future PR)
- Replace colors import with hardcoded hex values in components
- Migrate all files to use path aliases (@/components/*, @/hooks/*, etc.)
- Migrate SvgImage to use expo-image for better performance
- Update tsconfig.json to remove @/theme/* alias

* fix(companion): add path aliases to extension tsconfig

Add baseUrl and paths configuration to tsconfig.extension.json to support
path aliases in shared types used by the extension build.
2025-12-28 08:08:33 -03:00

107 lines
2.9 KiB
TypeScript

import * as Haptics from "expo-haptics";
import React, { useCallback } from "react";
import type { GestureResponderEvent, PressableProps, ViewStyle } from "react-native";
import { Pressable } from "react-native";
import Animated, {
type SharedValue,
useAnimatedStyle,
useSharedValue,
withTiming,
} from "react-native-reanimated";
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
type AppPressableProps = PressableProps & {
className?: string;
style?: ViewStyle;
enableHaptics?: boolean;
hapticStyle?: Haptics.ImpactFeedbackStyle;
/** @deprecated Use the built-in animation instead. Kept for backward compatibility. */
activeOpacity?: number;
};
function usePressAnimations(activeOpacity: number) {
const opacity = useSharedValue(1);
const scale = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [{ scale: scale.value }],
}));
const animatePressIn = useCallback(
(op: SharedValue<number>, sc: SharedValue<number>) => {
op.value = withTiming(activeOpacity, { duration: 100 });
sc.value = withTiming(0.98, { duration: 100 });
},
[activeOpacity]
);
const animatePressOut = useCallback((op: SharedValue<number>, sc: SharedValue<number>) => {
op.value = withTiming(1, { duration: 100 });
sc.value = withTiming(1, { duration: 100 });
}, []);
return { animatedStyle, animatePressIn, animatePressOut, opacity, scale };
}
export const AppPressable = React.forwardRef<React.ElementRef<typeof Pressable>, AppPressableProps>(
(
{
className,
style,
enableHaptics = true,
hapticStyle = Haptics.ImpactFeedbackStyle.Light,
activeOpacity = 0.7,
onPressIn,
onPressOut,
onPress,
...props
},
ref
) => {
const { animatedStyle, animatePressIn, animatePressOut, opacity, scale } =
usePressAnimations(activeOpacity);
const handlePressIn = useCallback(
(event: GestureResponderEvent) => {
animatePressIn(opacity, scale);
onPressIn?.(event);
},
[animatePressIn, onPressIn, opacity, scale]
);
const handlePressOut = useCallback(
(event: GestureResponderEvent) => {
animatePressOut(opacity, scale);
onPressOut?.(event);
},
[animatePressOut, onPressOut, opacity, scale]
);
const handlePress = useCallback(
(event: GestureResponderEvent) => {
if (enableHaptics) {
Haptics.impactAsync(hapticStyle);
}
onPress?.(event);
},
[enableHaptics, hapticStyle, onPress]
);
return (
<AnimatedPressable
ref={ref}
className={className}
style={[style, animatedStyle]}
onPressIn={handlePressIn}
onPressOut={handlePressOut}
onPress={handlePress}
{...props}
/>
);
}
);
AppPressable.displayName = "AppPressable";