I think it'll work
This commit is contained in:
@@ -260,6 +260,9 @@ export const styles = {
|
|||||||
...fontSize,
|
...fontSize,
|
||||||
...fontWeight,
|
...fontWeight,
|
||||||
...lineHeight,
|
...lineHeight,
|
||||||
|
center: {
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
flex: {
|
flex: {
|
||||||
gap,
|
gap,
|
||||||
@@ -281,6 +284,12 @@ export const styles = {
|
|||||||
alignCenter: {
|
alignCenter: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
|
alignStart: {
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
},
|
||||||
|
alignEnd: {
|
||||||
|
alignItems: 'flex-end',
|
||||||
|
},
|
||||||
justifyCenter: {
|
justifyCenter: {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
|
|||||||
+183
-16
@@ -1,32 +1,199 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Pressable, Text} from 'react-native'
|
import {Pressable, Text, PressableProps, TextProps} from 'react-native'
|
||||||
import {useAlf, tokens} from '#/alf'
|
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 {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 (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
{...rest}
|
{...rest}
|
||||||
style={[
|
style={state => [
|
||||||
styles.flex.row,
|
styles.flex.row,
|
||||||
styles.flex.gap.m,
|
styles.flex.alignCenter,
|
||||||
styles.padding.px.m,
|
...baseStyles,
|
||||||
styles.padding.py.s,
|
...(state.hovered ? hoverStyles : []),
|
||||||
styles.radius.m,
|
typeof style === 'function' ? style(state) : style,
|
||||||
styles.backgroundColor.primary,
|
]}
|
||||||
]}>
|
onPressIn={onPressIn}
|
||||||
|
onPressOut={onPressOut}
|
||||||
|
onHoverIn={onHoverIn}
|
||||||
|
onHoverOut={onHoverOut}
|
||||||
|
onFocus={onFocus}
|
||||||
|
onBlur={onBlur}>
|
||||||
{typeof children === 'string' ? (
|
{typeof children === 'string' ? (
|
||||||
<Text
|
<ButtonText type={type} size={size}>
|
||||||
style={[
|
|
||||||
styles.font.s,
|
|
||||||
styles.font.semi,
|
|
||||||
{color: tokens.color.white},
|
|
||||||
]}>
|
|
||||||
{children}
|
{children}
|
||||||
</Text>
|
</ButtonText>
|
||||||
|
) : typeof children === 'function' ? (
|
||||||
|
children({state, type, size})
|
||||||
) : (
|
) : (
|
||||||
children
|
children
|
||||||
)}
|
)}
|
||||||
</Pressable>
|
</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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
||||||
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
|
|
||||||
import {useSetColorMode} from '#/state/shell'
|
import {useSetColorMode} from '#/state/shell'
|
||||||
import {useAlf, ThemeProvider as Alf} from '#/alf'
|
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'
|
import {Text, H1, H2, H3, H4, H5, H6} from '#/view/com/Typography'
|
||||||
|
|
||||||
function ThemeSelector() {
|
function ThemeSelector() {
|
||||||
@@ -13,9 +14,24 @@ function ThemeSelector() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.flex.row, styles.flex.gap.m]}>
|
<View style={[styles.flex.row, styles.flex.gap.m]}>
|
||||||
<Button onPress={() => setColorMode('system')}>System</Button>
|
<Button
|
||||||
<Button onPress={() => setColorMode('light')}>Light</Button>
|
type="secondary"
|
||||||
<Button onPress={() => setColorMode('dark')}>Dark</Button>
|
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>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -269,6 +285,56 @@ export function DebugScreen() {
|
|||||||
<Alf theme="light">
|
<Alf theme="light">
|
||||||
<ThemedSection />
|
<ThemedSection />
|
||||||
</Alf>
|
</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>
|
</View>
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
Reference in New Issue
Block a user