tooot/src/components/Button.tsx

143 lines
3.6 KiB
TypeScript
Raw Permalink Normal View History

import Icon, { IconName } from '@components/Icon'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useState } from 'react'
2022-12-04 13:37:42 +01:00
import { AccessibilityProps, Pressable, StyleProp, View, ViewStyle } from 'react-native'
import { Loading } from './Loading'
import CustomText from './Text'
2020-12-03 01:28:56 +01:00
export type Props = {
2021-04-09 21:43:12 +02:00
accessibilityLabel?: AccessibilityProps['accessibilityLabel']
accessibilityHint?: AccessibilityProps['accessibilityHint']
2020-12-26 23:05:17 +01:00
style?: StyleProp<ViewStyle>
2021-04-09 21:43:12 +02:00
selected?: boolean
2020-12-26 23:05:17 +01:00
loading?: boolean
destructive?: boolean
disabled?: boolean
size?: 'S' | 'M' | 'L'
2022-06-03 23:18:24 +02:00
fontBold?: boolean
2020-12-26 23:05:17 +01:00
spacing?: 'XS' | 'S' | 'M' | 'L'
round?: boolean
overlay?: boolean
onPress: () => void
} & ({ type: 'icon'; content: IconName } | { type: 'text'; content: string })
2020-12-26 23:05:17 +01:00
const Button: React.FC<Props> = ({
2021-04-09 21:43:12 +02:00
accessibilityLabel,
accessibilityHint,
2020-12-26 23:05:17 +01:00
style: customStyle,
type,
content,
2021-04-09 21:43:12 +02:00
selected,
2020-12-26 23:05:17 +01:00
loading = false,
destructive = false,
disabled = false,
size = 'M',
2022-06-03 23:18:24 +02:00
fontBold = false,
2020-12-26 23:05:17 +01:00
spacing = 'S',
round = false,
overlay = false,
onPress
}) => {
const { colors } = useTheme()
2020-12-26 23:05:17 +01:00
const loadingSpinkit = () =>
loading ? (
2020-12-26 23:05:17 +01:00
<View style={{ position: 'absolute' }}>
<Loading />
2020-12-26 23:05:17 +01:00
</View>
) : null
2020-12-26 23:05:17 +01:00
const mainColor = () => {
2021-04-09 21:43:12 +02:00
if (selected) {
2022-02-12 14:51:01 +01:00
return colors.blue
2021-04-09 21:43:12 +02:00
} else if (overlay) {
2022-02-12 14:51:01 +01:00
return colors.primaryOverlay
2021-04-09 21:43:12 +02:00
} else if (disabled || loading) {
2022-02-12 14:51:01 +01:00
return colors.disabled
2021-01-07 19:13:09 +01:00
} else {
2021-04-09 21:43:12 +02:00
if (destructive) {
2022-02-12 14:51:01 +01:00
return colors.red
2021-01-07 19:13:09 +01:00
} else {
2022-02-12 14:51:01 +01:00
return colors.primaryDefault
2021-01-07 19:13:09 +01:00
}
}
}
2020-12-26 23:05:17 +01:00
const children = () => {
2020-12-26 23:05:17 +01:00
switch (type) {
case 'icon':
return (
<>
<Icon
name={content}
color={mainColor()}
2020-12-26 23:05:17 +01:00
style={{ opacity: loading ? 0 : 1 }}
size={StyleConstants.Font.Size[size] * (size === 'L' ? 1.25 : 1)}
2020-12-26 23:05:17 +01:00
/>
{loadingSpinkit()}
2020-12-26 23:05:17 +01:00
</>
)
case 'text':
return (
<>
<CustomText
2020-12-26 23:05:17 +01:00
style={{
color: mainColor(),
2022-12-04 13:37:42 +01:00
fontSize: StyleConstants.Font.Size[size] * (size === 'L' ? 1.25 : 1),
2020-12-26 23:05:17 +01:00
opacity: loading ? 0 : 1
}}
2023-01-08 16:59:35 +01:00
fontWeight={fontBold || selected ? 'Bold' : 'Normal'}
2020-12-26 23:05:17 +01:00
children={content}
2020-12-28 00:59:57 +01:00
testID='text'
2020-12-26 23:05:17 +01:00
/>
{loadingSpinkit()}
2020-12-26 23:05:17 +01:00
</>
)
}
}
2020-12-26 23:05:17 +01:00
2021-05-09 21:59:03 +02:00
const [layoutHeight, setLayoutHeight] = useState<number | undefined>()
2020-12-26 23:05:17 +01:00
return (
2021-01-16 00:00:31 +01:00
<Pressable
2021-04-09 21:43:12 +02:00
accessible
accessibilityLabel={accessibilityLabel}
accessibilityHint={accessibilityHint}
accessibilityRole='button'
accessibilityState={{
selected,
disabled: disabled || selected,
busy: loading
}}
2021-01-16 00:00:31 +01:00
style={[
{
2023-02-12 18:38:06 +01:00
borderRadius: 99,
justifyContent: 'center',
alignItems: 'center',
2023-01-08 16:59:35 +01:00
borderWidth: overlay ? 0 : selected ? 1.5 : 1,
borderColor: mainColor(),
backgroundColor: overlay ? colors.backgroundOverlayInvert : colors.backgroundDefault,
2021-01-16 00:00:31 +01:00
paddingVertical: StyleConstants.Spacing[spacing],
2022-12-04 13:37:42 +01:00
paddingHorizontal: StyleConstants.Spacing[spacing] + StyleConstants.Spacing.XS,
2021-05-09 21:59:03 +02:00
width: round && layoutHeight ? layoutHeight : undefined
2021-01-16 00:00:31 +01:00
},
customStyle
]}
2021-05-09 21:59:03 +02:00
{...(round && {
2022-12-04 13:37:42 +01:00
onLayout: ({ nativeEvent }) => setLayoutHeight(nativeEvent.layout.height)
2021-05-09 21:59:03 +02:00
})}
2021-01-16 00:00:31 +01:00
testID='base'
onPress={onPress}
children={children()}
2021-04-09 21:43:12 +02:00
disabled={selected || disabled || loading}
2021-01-16 00:00:31 +01:00
/>
2020-12-26 23:05:17 +01:00
)
}
export default Button