import { Fragment, forwardRef } from 'react' import { Pressable, View, type PressableProps } from 'react-native' import type { ColorPairToken } from '@helpwave/hightide-design/theme-tokens' import type { ComponentSize, ButtonVariant } from '@helpwave/hightide-design/semantic-token-resolvers' import { ContentThemeOverrideProvider } from '../../global-contexts/content-theme/ContentThemeProvider' import { useDebugContext } from '../../global-contexts/debug' import { useTheme } from '../../global-contexts/theme/ThemeContext' import type { IconComponent, IconStyle } from '../../icons/types' import type { ButtonState, ButtonStyle, ButtonTextStyle } from '../../theme/types/components/button' import type { StyleOverwrite } from '../../theme/types/resolver' import { createHitBoxOverlayStyle } from '../../utils/hitBoxOverlay' import { useMinimumTouchTargetHitSlop } from '../../utils/minimumTouchTargetHitSlop' import { ThemedIcon } from '../visualization-and-display/ThemedIcon' import { ThemedText } from '../visualization-and-display/ThemedText' export type ButtonSize = ComponentSize export type ButtonColor = ColorPairToken export const ButtonUtil = { sizes: ['xs', 'sm', 'md', 'lg', 'xl'] as const satisfies readonly ComponentSize[], variants: ['elevated', 'filled', 'tonal', 'outlined', 'foreground'] as const satisfies readonly ButtonVariant[], } export type ButtonProps = Omit & { size?: ButtonSize, color?: ButtonColor, variant?: ButtonVariant, children: string, leadingIcon?: IconComponent, trailingIcon?: IconComponent, style?: StyleOverwrite, stateLayerStyle?: StyleOverwrite, textStyle?: StyleOverwrite, iconStyle?: StyleOverwrite, } type PressableInteraction = { pressed: boolean, hovered?: boolean, focused?: boolean, focusVisible?: boolean, } export const Button = forwardRef, ButtonProps>(function Button({ children, size = 'md', color, variant = 'filled', disabled, leadingIcon, trailingIcon, style, stateLayerStyle, textStyle, iconStyle, hitSlop: providedHitSlop, onLayout: providedOnLayout, ...props }, ref) { const { theme } = useTheme() const { hitBox } = useDebugContext() const { hitSlop, onLayout } = useMinimumTouchTargetHitSlop({ touchTargetSize: theme.semantics.touchTargetSize({}), hitSlop: providedHitSlop, onLayout: providedOnLayout, }) const resolveState = (interaction: PressableInteraction): ButtonState => ({ size, color, variant, isDisabled: !!disabled, isPressed: interaction.pressed, isHovered: !!interaction.hovered, isFocused: !!interaction.focused, isFocusVisible: !!interaction.focusVisible, }) return ( { const state = resolveState(pressableState as PressableInteraction) return theme.components.button.container(state, style) }} > {(pressableState) => { const state = resolveState(pressableState as PressableInteraction) const resolvedText = theme.components.button.text(state, textStyle) const resolvedIcon = theme.components.button.icon(state, iconStyle) return ( {hitBox.isVisualizing && ( )} {leadingIcon !== undefined && ( )} {children} {trailingIcon !== undefined && ( )} ) }} ) })