I think it'll work

This commit is contained in:
Eric Bailey
2023-12-21 15:52:46 -06:00
parent 96e81854fa
commit b3e19afd63
3 changed files with 262 additions and 20 deletions
+9
View File
@@ -260,6 +260,9 @@ export const styles = {
...fontSize,
...fontWeight,
...lineHeight,
center: {
textAlign: 'center',
},
},
flex: {
gap,
@@ -281,6 +284,12 @@ export const styles = {
alignCenter: {
alignItems: 'center',
},
alignStart: {
alignItems: 'flex-start',
},
alignEnd: {
alignItems: 'flex-end',
},
justifyCenter: {
justifyContent: 'center',
},
+183 -16
View File
@@ -1,32 +1,199 @@
import React from 'react'
import {Pressable, Text} from 'react-native'
import {Pressable, Text, PressableProps, TextProps} from 'react-native'
import {useAlf, tokens} from '#/alf'
export function Button({children, ...rest}: React.PropsWithChildren<any>) {
export type ButtonType =
| 'primary'
| 'secondary'
| 'tertiary'
| 'positive'
| 'negative'
export type ButtonSize = 'small' | 'large'
export type VariantProps = {
type?: ButtonType
size?: ButtonSize
}
type ButtonState = {
pressed: boolean
hovered: boolean
focused: boolean
}
export type ButtonProps = Omit<PressableProps, 'children'> &
VariantProps & {
children:
| ((props: {
state: ButtonState
type?: ButtonType
size?: ButtonSize
}) => React.ReactNode)
| React.ReactNode
| string
}
export type ButtonTextProps = TextProps & VariantProps
export function Button({children, style, type, size, ...rest}: ButtonProps) {
const {styles} = useAlf()
const {baseStyles, hoverStyles} = React.useMemo(() => {
const baseStyles = []
const hoverStyles = []
switch (type) {
case 'primary':
baseStyles.push(styles.backgroundColor.primary)
break
case 'secondary':
baseStyles.push(styles.backgroundColor.l2)
hoverStyles.push(styles.backgroundColor.l1)
break
default:
}
switch (size) {
case 'large':
baseStyles.push(
styles.padding.py.m,
styles.padding.px.xl,
styles.radius.m,
styles.flex.gap.s,
)
break
case 'small':
baseStyles.push(
styles.padding.py.s,
styles.padding.px.m,
styles.radius.s,
styles.flex.gap.xs,
)
break
default:
}
return {
baseStyles,
hoverStyles,
}
}, [type, size, styles])
const [state, setState] = React.useState({
pressed: false,
hovered: false,
focused: false,
})
const onPressIn = React.useCallback(() => {
setState(s => ({
...s,
pressed: true,
}))
}, [setState])
const onPressOut = React.useCallback(() => {
setState(s => ({
...s,
pressed: false,
}))
}, [setState])
const onHoverIn = React.useCallback(() => {
setState(s => ({
...s,
hovered: true,
}))
}, [setState])
const onHoverOut = React.useCallback(() => {
setState(s => ({
...s,
hovered: false,
}))
}, [setState])
const onFocus = React.useCallback(() => {
setState(s => ({
...s,
focused: true,
}))
}, [setState])
const onBlur = React.useCallback(() => {
setState(s => ({
...s,
focused: false,
}))
}, [setState])
return (
<Pressable
{...rest}
style={[
style={state => [
styles.flex.row,
styles.flex.gap.m,
styles.padding.px.m,
styles.padding.py.s,
styles.radius.m,
styles.backgroundColor.primary,
]}>
styles.flex.alignCenter,
...baseStyles,
...(state.hovered ? hoverStyles : []),
typeof style === 'function' ? style(state) : style,
]}
onPressIn={onPressIn}
onPressOut={onPressOut}
onHoverIn={onHoverIn}
onHoverOut={onHoverOut}
onFocus={onFocus}
onBlur={onBlur}>
{typeof children === 'string' ? (
<Text
style={[
styles.font.s,
styles.font.semi,
{color: tokens.color.white},
]}>
<ButtonText type={type} size={size}>
{children}
</Text>
</ButtonText>
) : typeof children === 'function' ? (
children({state, type, size})
) : (
children
)}
</Pressable>
)
}
export function ButtonText({
children,
style,
type,
size,
...rest
}: ButtonTextProps) {
const {styles} = useAlf()
const textStyles = React.useMemo(() => {
const base = []
switch (type) {
case 'primary':
base.push({color: tokens.color.white})
break
case 'secondary':
base.push(styles.color.l5)
break
default:
}
switch (size) {
case 'small':
base.push(styles.font.s, {paddingBottom: 1})
break
case 'large':
base.push(styles.font.m, {paddingBottom: 1})
break
default:
}
return base
}, [type, size, styles])
console.log(textStyles)
return (
<Text
{...rest}
style={[
styles.flex.one,
styles.font.semi,
styles.font.center,
...textStyles,
style,
]}>
{children}
</Text>
)
}
+70 -4
View File
@@ -1,10 +1,11 @@
import React from 'react'
import {View} from 'react-native'
import {CenteredView, ScrollView} from '#/view/com/util/Views'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {useSetColorMode} from '#/state/shell'
import {useAlf, ThemeProvider as Alf} from '#/alf'
import {Button} from '#/view/com/Button'
import {Button, ButtonText} from '#/view/com/Button'
import {Text, H1, H2, H3, H4, H5, H6} from '#/view/com/Typography'
function ThemeSelector() {
@@ -13,9 +14,24 @@ function ThemeSelector() {
return (
<View style={[styles.flex.row, styles.flex.gap.m]}>
<Button onPress={() => setColorMode('system')}>System</Button>
<Button onPress={() => setColorMode('light')}>Light</Button>
<Button onPress={() => setColorMode('dark')}>Dark</Button>
<Button
type="secondary"
size="small"
onPress={() => setColorMode('system')}>
System
</Button>
<Button
type="secondary"
size="small"
onPress={() => setColorMode('light')}>
Light
</Button>
<Button
type="secondary"
size="small"
onPress={() => setColorMode('dark')}>
Dark
</Button>
</View>
)
}
@@ -269,6 +285,56 @@ export function DebugScreen() {
<Alf theme="light">
<ThemedSection />
</Alf>
<View style={[styles.flex.gap.m, styles.flex.alignStart]}>
<H3 style={[styles.padding.pb.m, styles.font.bold]}>Buttons</H3>
<Button>
{({state}) => (
<View
style={[
styles.padding.pa.m,
styles.radius.round,
styles.backgroundColor.l2,
]}>
<Text>Unstyled button, state: {JSON.stringify(state)}</Text>
</View>
)}
</Button>
<Button type="primary" size="small">
Button
</Button>
<Button type="secondary" size="small">
Button
</Button>
<Button type="primary" size="large">
Button
</Button>
<Button type="secondary" size="large">
Button
</Button>
<Button type="secondary" size="small">
{({type, size}) => (
<>
<FontAwesomeIcon icon={['fas', 'plus']} size={12} />
<ButtonText type={type} size={size}>
With an icon
</ButtonText>
</>
)}
</Button>
<Button type="primary" size="large">
{({state: _state, ...rest}) => (
<>
<FontAwesomeIcon icon={['fas', 'plus']} />
<ButtonText {...rest}>With an icon</ButtonText>
</>
)}
</Button>
</View>
</View>
</CenteredView>
</ScrollView>