diff --git a/js/app/components/follow-button.tsx b/js/app/components/follow-button.tsx index 0c64ccf3..7b3bd9ca 100644 --- a/js/app/components/follow-button.tsx +++ b/js/app/components/follow-button.tsx @@ -123,11 +123,12 @@ const FollowButton: React.FC = ({ disabled={isFollowing === null} loading={isFollowing === null} leftIcon={!isFollowing && } + hoverStyle={isFollowing ? { backgroundColor: "#dc2626" } : undefined} > {isFollowing === null ? "Loading..." : isFollowing - ? "Unfollow" + ? "Following" : "Follow"} {error && {error}} diff --git a/js/components/src/components/ui/button.tsx b/js/components/src/components/ui/button.tsx index ac4e532b..3b2182e5 100644 --- a/js/components/src/components/ui/button.tsx +++ b/js/components/src/components/ui/button.tsx @@ -41,6 +41,7 @@ export interface ButtonProps loading?: boolean; loadingText?: string; width?: "full" | "min" | number; + hoverStyle?: ButtonPrimitiveProps["hoverStyle"]; } export const Button = forwardRef( @@ -56,6 +57,7 @@ export const Button = forwardRef( disabled, style, width = "full", + hoverStyle, ...props }, ref, @@ -222,6 +224,7 @@ export const Button = forwardRef( ref={ref} disabled={disabled || loading} style={[buttonStyle, sizeStyles.button, widthStyle, style]} + hoverStyle={hoverStyle} {...props} > diff --git a/js/components/src/components/ui/primitives/button.tsx b/js/components/src/components/ui/primitives/button.tsx index 674c6ac7..0934a9fe 100644 --- a/js/components/src/components/ui/primitives/button.tsx +++ b/js/components/src/components/ui/primitives/button.tsx @@ -1,19 +1,21 @@ -import React, { forwardRef } from "react"; +import React, { forwardRef, useState } from "react"; import { AccessibilityRole, GestureResponderEvent, + Platform, + Pressable, + PressableProps, + StyleProp, StyleSheet, Text, TextProps, - TouchableOpacity, - TouchableOpacityProps, View, ViewProps, + ViewStyle, } from "react-native"; // Base button primitive interface -export interface ButtonPrimitiveProps - extends Omit { +export interface ButtonPrimitiveProps extends Omit { onPress?: (event: GestureResponderEvent) => void; disabled?: boolean; loading?: boolean; @@ -21,11 +23,12 @@ export interface ButtonPrimitiveProps accessibilityLabel?: string; accessibilityHint?: string; testID?: string; + hoverStyle?: StyleProp; } // Button root primitive - handles all touch interactions export const ButtonRoot = forwardRef< - React.ComponentRef, + React.ComponentRef, ButtonPrimitiveProps >( ( @@ -43,11 +46,13 @@ export const ButtonRoot = forwardRef< accessibilityState, testID, style, - activeOpacity = 0.7, + hoverStyle, ...props }, ref, ) => { + const [isHovered, setIsHovered] = useState(false); + const handlePress = React.useCallback( (event: GestureResponderEvent) => { if (!disabled && !loading && onPress) { @@ -84,15 +89,26 @@ export const ButtonRoot = forwardRef< [disabled, loading, onLongPress], ); + const handleHoverIn = React.useCallback(() => { + if (!disabled && !loading) { + setIsHovered(true); + } + }, [disabled, loading]); + + const handleHoverOut = React.useCallback(() => { + setIsHovered(false); + }, []); + return ( - {children} - + ); }, ); @@ -245,6 +263,14 @@ const primitiveStyles = StyleSheet.create({ alignItems: "center", justifyContent: "center", }, + transition: + Platform.OS === "web" + ? // probably fine if web-only + ({ + transitionDuration: "150ms", + transitionProperty: "background-color, border-color, color", + } as any) + : undefined, disabled: { opacity: 0.5, },