import { ComponentType, useEffect, useRef } from "react" import { Animated, Pressable, PressableProps, PressableStateCallbackType, StyleProp, TextStyle, View, ViewStyle, } from "react-native" import { useAppTheme } from "@/theme/context" import { $styles } from "@/theme/styles" import type { ThemedStyle, ThemedStyleArray } from "@/theme/types" import { s, fs } from "@/utils/responsive" import { Text, TextProps } from "./Text" /** * Three-dot loading animation component */ function LoadingDots({ color }: { color: string }) { const dot1 = useRef(new Animated.Value(0)).current const dot2 = useRef(new Animated.Value(0)).current const dot3 = useRef(new Animated.Value(0)).current useEffect(() => { const animateDot = (dot: Animated.Value, delay: number) => { return Animated.loop( Animated.sequence([ Animated.delay(delay), Animated.timing(dot, { toValue: 1, duration: 300, useNativeDriver: true, }), Animated.timing(dot, { toValue: 0, duration: 300, useNativeDriver: true, }), ]), ) } const animation = Animated.parallel([ animateDot(dot1, 0), animateDot(dot2, 150), animateDot(dot3, 300), ]) animation.start() return () => animation.stop() }, [dot1, dot2, dot3]) const dotStyle = (animatedValue: Animated.Value) => ({ width: s(8), height: s(8), borderRadius: s(4), backgroundColor: color, marginHorizontal: 3, opacity: animatedValue.interpolate({ inputRange: [0, 1], outputRange: [0.3, 1], }), transform: [ { scale: animatedValue.interpolate({ inputRange: [0, 1], outputRange: [0.8, 1.2], }), }, ], }) return ( ) } type Presets = "default" | "filled" | "reversed" | "link" export interface ButtonAccessoryProps { style: StyleProp pressableState: PressableStateCallbackType disabled?: boolean } export interface ButtonProps extends PressableProps { /** * Text which is looked up via i18n. */ tx?: TextProps["tx"] /** * The text to display if not using `tx` or nested components. */ text?: TextProps["text"] /** * Optional options to pass to i18n. Useful for interpolation * as well as explicitly setting locale or translation fallbacks. */ txOptions?: TextProps["txOptions"] /** * An optional style override useful for padding & margin. */ style?: StyleProp /** * An optional style override for the "pressed" state. */ pressedStyle?: StyleProp /** * An optional style override for the button text. */ textStyle?: StyleProp /** * An optional style override for the button text when in the "pressed" state. */ pressedTextStyle?: StyleProp /** * An optional style override for the button text when in the "disabled" state. */ disabledTextStyle?: StyleProp /** * One of the different types of button presets. */ preset?: Presets /** * An optional component to render on the right side of the text. * Example: `RightAccessory={(props) => }` */ RightAccessory?: ComponentType /** * An optional component to render on the left side of the text. * Example: `LeftAccessory={(props) => }` */ LeftAccessory?: ComponentType /** * Children components. */ children?: React.ReactNode /** * disabled prop, accessed directly for declarative styling reasons. * https://reactnative.dev/docs/pressable#disabled */ disabled?: boolean /** * An optional style override for the disabled state */ disabledStyle?: StyleProp /** * Show loading state with animated dots */ loading?: boolean } /** * A component that allows users to take actions and make choices. * Wraps the Text component with a Pressable component. * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Button/} * @param {ButtonProps} props - The props for the `Button` component. * @returns {JSX.Element} The rendered `Button` component. * @example *