New component library based on ALF (#2459)
* Install on native as well * Add button and link components * Comments * Use new prop * Add some form elements * Add labels to input * Fix line height, add suffix * Date inputs * Autofill styles * Clean up InputDate types * Improve types for InputText, value handling * Enforce a11y props on buttons * Add Dialog, Portal * Dialog contents * Native dialog * Clean up * Fix animations * Improvements to web modal, exiting still broken * Clean up dialog types * Add Prompt, Dialog refinement, mobile refinement * Integrate new design tokens, reorg storybook * Button colors * Dim mode * Reorg * Some styles * Toggles * Improve a11y * Autosize dialog, handle max height, Dialog.ScrolLView not working * Try to use BottomSheet's own APIs * Scrollable dialogs * Add web shadow * Handle overscroll * Styles * Dialog text input * Shadows * Button focus states * Button pressed states * Gradient poc * Gradient colors and hovers * Add hrefAttrs to Link * Some more a11y * Toggle invalid states * Update dialog descriptions for demo * Icons * WIP Toggle cleanup * Refactor toggle to not rely on immediate children * Make Toggle controlled * Clean up Toggles storybook * ToggleButton styles * Improve a11y labels * ToggleButton hover darkmode * Some i18n * Refactor input * Allow extension of input * Remove old input * Improve icons, add CalendarDays * Refactor DateField, web done * Add label example * Clean up old InputDate, DateField android, text area example * Consistent imports * Button context, icons * Add todo * Add closeAllDialogs control * Alignment * Expand color palette * Hitslops, add shortcut to Storybook in dev * Fix multiline on ios * Mark dialog close button as unused
This commit is contained in:
parent
9cbd3c0937
commit
66b8774ecb
60 changed files with 4683 additions and 968 deletions
|
@ -1,204 +0,0 @@
|
|||
import React from 'react'
|
||||
import {Pressable, Text, PressableProps, TextProps} from 'react-native'
|
||||
import * as tokens from '#/alf/tokens'
|
||||
import {atoms} from '#/alf'
|
||||
|
||||
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 {baseStyles, hoverStyles} = React.useMemo(() => {
|
||||
const baseStyles = []
|
||||
const hoverStyles = []
|
||||
|
||||
switch (type) {
|
||||
case 'primary':
|
||||
baseStyles.push({
|
||||
backgroundColor: tokens.color.blue_500,
|
||||
})
|
||||
break
|
||||
case 'secondary':
|
||||
baseStyles.push({
|
||||
backgroundColor: tokens.color.gray_200,
|
||||
})
|
||||
hoverStyles.push({
|
||||
backgroundColor: tokens.color.gray_100,
|
||||
})
|
||||
break
|
||||
default:
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 'large':
|
||||
baseStyles.push(
|
||||
atoms.py_md,
|
||||
atoms.px_xl,
|
||||
atoms.rounded_md,
|
||||
atoms.gap_sm,
|
||||
)
|
||||
break
|
||||
case 'small':
|
||||
baseStyles.push(
|
||||
atoms.py_sm,
|
||||
atoms.px_md,
|
||||
atoms.rounded_sm,
|
||||
atoms.gap_xs,
|
||||
)
|
||||
break
|
||||
default:
|
||||
}
|
||||
|
||||
return {
|
||||
baseStyles,
|
||||
hoverStyles,
|
||||
}
|
||||
}, [type, size])
|
||||
|
||||
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={state => [
|
||||
atoms.flex_row,
|
||||
atoms.align_center,
|
||||
...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' ? (
|
||||
<ButtonText type={type} size={size}>
|
||||
{children}
|
||||
</ButtonText>
|
||||
) : typeof children === 'function' ? (
|
||||
children({state, type, size})
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</Pressable>
|
||||
)
|
||||
}
|
||||
|
||||
export function ButtonText({
|
||||
children,
|
||||
style,
|
||||
type,
|
||||
size,
|
||||
...rest
|
||||
}: ButtonTextProps) {
|
||||
const textStyles = React.useMemo(() => {
|
||||
const base = []
|
||||
|
||||
switch (type) {
|
||||
case 'primary':
|
||||
base.push({color: tokens.color.white})
|
||||
break
|
||||
case 'secondary':
|
||||
base.push({
|
||||
color: tokens.color.gray_700,
|
||||
})
|
||||
break
|
||||
default:
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 'small':
|
||||
base.push(atoms.text_sm, {paddingBottom: 1})
|
||||
break
|
||||
case 'large':
|
||||
base.push(atoms.text_md, {paddingBottom: 1})
|
||||
break
|
||||
default:
|
||||
}
|
||||
|
||||
return base
|
||||
}, [type, size])
|
||||
|
||||
return (
|
||||
<Text
|
||||
{...rest}
|
||||
style={[
|
||||
atoms.flex_1,
|
||||
atoms.font_semibold,
|
||||
atoms.text_center,
|
||||
...textStyles,
|
||||
style,
|
||||
]}>
|
||||
{children}
|
||||
</Text>
|
||||
)
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
import React from 'react'
|
||||
import {Text as RNText, TextProps} from 'react-native'
|
||||
import {useTheme, atoms, web} from '#/alf'
|
||||
|
||||
export function Text({style, ...rest}: TextProps) {
|
||||
const t = useTheme()
|
||||
return <RNText style={[atoms.text_sm, t.atoms.text, style]} {...rest} />
|
||||
}
|
||||
|
||||
export function H1({style, ...rest}: TextProps) {
|
||||
const t = useTheme()
|
||||
const attr =
|
||||
web({
|
||||
role: 'heading',
|
||||
'aria-level': 1,
|
||||
}) || {}
|
||||
return (
|
||||
<RNText
|
||||
{...attr}
|
||||
{...rest}
|
||||
style={[atoms.text_xl, atoms.font_bold, t.atoms.text, style]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function H2({style, ...rest}: TextProps) {
|
||||
const t = useTheme()
|
||||
const attr =
|
||||
web({
|
||||
role: 'heading',
|
||||
'aria-level': 2,
|
||||
}) || {}
|
||||
return (
|
||||
<RNText
|
||||
{...attr}
|
||||
{...rest}
|
||||
style={[atoms.text_lg, atoms.font_bold, t.atoms.text, style]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function H3({style, ...rest}: TextProps) {
|
||||
const t = useTheme()
|
||||
const attr =
|
||||
web({
|
||||
role: 'heading',
|
||||
'aria-level': 3,
|
||||
}) || {}
|
||||
return (
|
||||
<RNText
|
||||
{...attr}
|
||||
{...rest}
|
||||
style={[atoms.text_md, atoms.font_bold, t.atoms.text, style]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function H4({style, ...rest}: TextProps) {
|
||||
const t = useTheme()
|
||||
const attr =
|
||||
web({
|
||||
role: 'heading',
|
||||
'aria-level': 4,
|
||||
}) || {}
|
||||
return (
|
||||
<RNText
|
||||
{...attr}
|
||||
{...rest}
|
||||
style={[atoms.text_sm, atoms.font_bold, t.atoms.text, style]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function H5({style, ...rest}: TextProps) {
|
||||
const t = useTheme()
|
||||
const attr =
|
||||
web({
|
||||
role: 'heading',
|
||||
'aria-level': 5,
|
||||
}) || {}
|
||||
return (
|
||||
<RNText
|
||||
{...attr}
|
||||
{...rest}
|
||||
style={[atoms.text_xs, atoms.font_bold, t.atoms.text, style]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function H6({style, ...rest}: TextProps) {
|
||||
const t = useTheme()
|
||||
const attr =
|
||||
web({
|
||||
role: 'heading',
|
||||
'aria-level': 6,
|
||||
}) || {}
|
||||
return (
|
||||
<RNText
|
||||
{...attr}
|
||||
{...rest}
|
||||
style={[atoms.text_xxs, atoms.font_bold, t.atoms.text, style]}
|
||||
/>
|
||||
)
|
||||
}
|
|
@ -20,6 +20,11 @@ import {useNavigation} from '@react-navigation/native'
|
|||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {Logo} from '#/view/icons/Logo'
|
||||
|
||||
import {IS_DEV} from '#/env'
|
||||
import {atoms} from '#/alf'
|
||||
import {Link as Link2} from '#/components/Link'
|
||||
import {ColorPalette_Stroke2_Corner0_Rounded as ColorPalette} from '#/components/icons/ColorPalette'
|
||||
|
||||
export function FeedsTabBar(
|
||||
props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
|
||||
) {
|
||||
|
@ -68,7 +73,7 @@ export function FeedsTabBar(
|
|||
headerHeight.value = e.nativeEvent.layout.height
|
||||
}}>
|
||||
<View style={[pal.view, styles.topBar]}>
|
||||
<View style={[pal.view]}>
|
||||
<View style={[pal.view, {width: 100}]}>
|
||||
<TouchableOpacity
|
||||
testID="viewHeaderDrawerBtn"
|
||||
onPress={onPressAvi}
|
||||
|
@ -88,7 +93,21 @@ export function FeedsTabBar(
|
|||
<View>
|
||||
<Logo width={30} />
|
||||
</View>
|
||||
<View style={[pal.view, {width: 18}]}>
|
||||
<View
|
||||
style={[
|
||||
atoms.flex_row,
|
||||
atoms.justify_end,
|
||||
atoms.align_center,
|
||||
atoms.gap_md,
|
||||
pal.view,
|
||||
{width: 100},
|
||||
]}>
|
||||
{IS_DEV && (
|
||||
<Link2 to="/sys/debug">
|
||||
<ColorPalette size="md" />
|
||||
</Link2>
|
||||
)}
|
||||
|
||||
{hasSession && (
|
||||
<Link
|
||||
testID="viewHeaderHomeFeedPrefsBtn"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue