/** * Copyright (c) 2019 Paul Armstrong */ import * as Theme from '../theme'; import Hoverable from './Hoverable'; import React from 'react'; import Ripple from './Ripple'; import { StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'; interface Props { accessibilityLabel?: string; color?: 'primary' | 'secondary'; disabled?: boolean; icon?: React.ComponentType<{ style?: StyleProp }>; iconOnly?: boolean; onPress?: (event: MouseEvent) => void; style?: StyleProp; testID?: string; title: string; type?: 'text' | 'raised' | 'unelevated' | 'outlined' | 'shape' | 'shapeRaised'; } const Button = (props: Props): React.ReactElement => { const [isActive, setIsActive] = React.useState(false); const { accessibilityLabel, color = 'primary', disabled = false, icon: Icon, iconOnly, onPress, style, title, type = 'text', } = props; const rippleColor = ['outlined', 'text'].indexOf(type) !== -1 ? Theme.Color.Gray30 : color === 'primary' ? Theme.Color.Primary20 : Theme.Color.Secondary20; const _getRootStyles = (isHovered: boolean): Array> => _getStyles(rootStyles, isHovered); const _getTextStyles = (isHovered: boolean): Array> => _getStyles(textStyles, isHovered); const _getIconStyles = (isHovered: boolean): Array> => _getStyles(iconStyles, isHovered); const _getStyles = ( styles: typeof rootStyles | typeof textStyles | typeof iconStyles, isHovered: boolean ): Array> => { const isRaised = ['raised', 'shapeRaised'].indexOf(type) !== -1; const isBg = ['raised', 'unelevated', 'shape', 'shapeRaised'].indexOf(type) !== -1; return [ styles[type], // @ts-ignore !disabled && isHovered && styles.rootHover, // @ts-ignore !disabled && isActive && styles.rootActive, styles[color], disabled && styles[`${color}Disabled`], // @ts-ignore isRaised && styles.raised, isRaised && styles[`raised${color}`], // @ts-ignore isBg && styles.bg, isBg && styles[`bg${color}`], styles[`${type}${color}`], !disabled && isHovered && styles[`${type}Hover`], !disabled && isHovered && styles[`${type}${color}Hover`], !disabled && isHovered && isRaised && styles['raisedHover'], !disabled && isHovered && isRaised && styles[`raised${color}Hover`], !disabled && isHovered && isBg && styles['bgHover'], !disabled && isHovered && isBg && styles[`bg${color}Hover`], !disabled && isActive && styles[`${type}Active`], !disabled && isActive && styles[`${type}${color}Active`], !disabled && isActive && isRaised && styles['raisedActive'], !disabled && isActive && isRaised && styles[`raised${color}Active`], ]; }; const _handlePress = React.useCallback( (event): void => { if (disabled) { return; } onPress && onPress(event); }, [disabled, onPress] ); const _handlePressIn = React.useCallback(() => { setIsActive(true); }, []); const _handlePressOut = React.useCallback(() => { setIsActive(false); }, []); return ( {(isHovered) => ( {Icon ? ( ) : null} {iconOnly ? null : title} )} ); }; const rootStyles = StyleSheet.create({ root: { display: 'inline-flex', borderRadius: Theme.BorderRadius.Normal, boxSizing: 'border-box', transitionProperty: 'background-color, box-shadow, border-color', transitionDuration: '0.2s, 0.2s, 0.2s', transitionTimingFunction: Theme.MotionTiming.Standard, height: '100%', position: 'relative', }, iconOnly: { flexShrink: 0, }, content: { flexDirection: 'row', height: '2.5rem', paddingHorizontal: Theme.Spacing.Normal, alignItems: 'center', justifyContent: 'center', }, contentIconOnly: { width: '2.5rem', paddingHorizontal: Theme.Spacing.None, }, rootHover: { backgroundColor: 'rgba(0,0,0,0.1)', }, outlined: { borderWidth: 2, borderColor: Theme.Color.Primary40, }, outlinedHover: { borderColor: Theme.Color.Primary60, }, outlinedActive: { borderColor: Theme.Color.Primary10, }, outlinedsecondary: { borderColor: Theme.Color.Secondary40, }, outlinedsecondaryHover: { borderColor: Theme.Color.Secondary60, }, outlinedsecondaryActive: { borderColor: Theme.Color.Secondary10, }, raised: { shadowOffset: { width: 0, height: 2 }, shadowColor: Theme.Color.Black, shadowOpacity: 0.3, shadowRadius: 5, }, raisedHover: { shadowOffset: { width: 0, height: 4 }, shadowRadius: 10, }, raisedActive: { shadowOffset: { width: 0, height: 2 }, shadowRadius: 3, }, shape: { borderRadius: Theme.BorderRadius.Infinite, }, shapeRaised: { borderRadius: Theme.BorderRadius.Infinite, }, // Primary40 colors bgprimary: { backgroundColor: Theme.Color.Primary40, }, bgprimaryHover: { backgroundColor: Theme.Color.Primary30, }, // Secondary40colors bgsecondary: { backgroundColor: Theme.Color.Secondary40, }, bgsecondaryHover: { backgroundColor: Theme.Color.Secondary30, }, }); const textStyles = StyleSheet.create({ root: { fontWeight: '500', color: Theme.TextColor.White, textTransform: 'uppercase', }, primary: { color: Theme.Color.Primary40, }, primaryDisabled: { color: Theme.Color.Gray30, }, secondary: { color: Theme.Color.Secondary40, }, secondaryDisabled: { color: Theme.Color.Gray30, }, bgprimary: { color: Theme.TextColor.Primary40, }, bgsecondary: { color: Theme.TextColor.Secondary40, }, }); const iconStyles = StyleSheet.create({ withText: { marginEnd: '0.5rem', marginStart: '-0.25rem', }, iconOnly: { fontSize: Theme.FontSize.Medium, }, primary: { color: Theme.Color.Primary40, }, primaryDisabled: { color: Theme.Color.Gray30, }, secondary: { color: Theme.Color.Secondary40, }, secondaryDisabled: { color: Theme.Color.Gray30, }, bgprimary: { color: Theme.TextColor.Primary40, }, bgsecondary: { color: Theme.TextColor.Secondary40, }, }); export default Button;