import React from 'react';
import { ActivityIndicator, View as ReactNativeView, type ViewStyle } from 'react-native';
import {
resolveButtonColors,
resolveControlSize,
resolveIconSize,
} from '../../../../internal/resolvers';
import type { ButtonProps } from '../../../../types/button';
import type { InteractionState } from '../../../../types/pressable';
import type { SurfaceTheme } from '../../../../types/theme';
import { Icon } from '../../../icon/public';
import { View } from '../../../layout/public';
import { Pressable } from '../../../pressable/public';
import { useTheme } from '../../../theme/runtime';
import { Text } from '../../../typography/public';
/*** Renders the primary Surface action control with semantic visual states. */
export function Button({
children,
variant = 'solid',
color = 'primary',
size = 'm',
disabled = false,
loading = false,
leadingIcon,
trailingIcon,
fullWidth = false,
onPress,
testID,
...props
}: ButtonProps) {
const { theme } = useTheme();
const controlSize = resolveControlSize(theme, size);
return (
{(state) => (
{children}
)}
);
}
/*** Renders Button content after interaction colors have been resolved. */
function ButtonContent({
children,
color,
controlSize,
fullWidth,
leadingIcon,
loading,
size,
state,
theme,
trailingIcon,
variant,
}: ButtonContentProps) {
const colors = resolveButtonColors(theme, { variant, color, state });
const iconSize = resolveIconSize(theme, size);
return (
{loading ? (
) : (
<>
{leadingIcon ? (
) : null}
{children}
{trailingIcon ? (
) : null}
>
)}
);
}
/*** Resolves the outer Pressable layout style. */
function resolvePressableStyle(fullWidth: boolean): ViewStyle {
return { alignSelf: fullWidth ? 'stretch' : 'flex-start' };
}
/*** Resolves the themed Button content container style. */
function resolveButtonContentStyle(
controlSize: ReturnType,
colors: ReturnType,
fullWidth: boolean,
variant: NonNullable,
): ViewStyle {
return {
alignItems: 'center',
backgroundColor: colors.backgroundColor,
borderColor: colors.borderColor,
borderWidth: variant === 'solid' ? 0 : 1,
flexDirection: 'row',
justifyContent: 'center',
minHeight: controlSize.minHeight,
opacity: colors.opacity,
width: fullWidth ? '100%' : undefined,
};
}
/*** Resolves spacing around a leading or trailing Button icon. */
function resolveAccessoryStyle(spacing: number, position: 'leading' | 'trailing'): ViewStyle {
return position === 'leading' ? { marginRight: spacing } : { marginLeft: spacing };
}
interface ButtonContentProps {
children: ButtonProps['children'];
color: NonNullable;
controlSize: ReturnType;
fullWidth: boolean;
leadingIcon: ButtonProps['leadingIcon'];
loading: boolean;
size: NonNullable;
state: InteractionState;
theme: SurfaceTheme;
trailingIcon: ButtonProps['trailingIcon'];
variant: NonNullable;
}