Enforce that text is wrapped in <Text>, remaining cases (#3421)
* Toggle.Button -> Toggle.ButtonWithText * Simplify Prompt.Cancel/Action * Move lines down for better diff * Remove ButtonWithText * Simplify types * Enforce Button/ButtonText nesting * Add suggested wrapper in linter error * Check <Trans> ancestry too * Also check literals * Rm ts-ignore
This commit is contained in:
parent
49266c355e
commit
46c112edfd
15 changed files with 589 additions and 75 deletions
|
@ -12,7 +12,6 @@ import {
|
|||
ViewStyle,
|
||||
} from 'react-native'
|
||||
import {LinearGradient} from 'expo-linear-gradient'
|
||||
import {Trans} from '@lingui/macro'
|
||||
|
||||
import {android, atoms as a, flatten, tokens, useTheme} from '#/alf'
|
||||
import {Props as SVGIconProps} from '#/components/icons/common'
|
||||
|
@ -59,6 +58,10 @@ export type ButtonState = {
|
|||
|
||||
export type ButtonContext = VariantProps & ButtonState
|
||||
|
||||
type NonTextElements =
|
||||
| React.ReactElement
|
||||
| Iterable<React.ReactElement | null | undefined | boolean>
|
||||
|
||||
export type ButtonProps = Pick<
|
||||
PressableProps,
|
||||
'disabled' | 'onPress' | 'testID'
|
||||
|
@ -68,11 +71,9 @@ export type ButtonProps = Pick<
|
|||
testID?: string
|
||||
label: string
|
||||
style?: StyleProp<ViewStyle>
|
||||
children:
|
||||
| React.ReactNode
|
||||
| string
|
||||
| ((context: ButtonContext) => React.ReactNode | string)
|
||||
children: NonTextElements | ((context: ButtonContext) => NonTextElements)
|
||||
}
|
||||
|
||||
export type ButtonTextProps = TextProps & VariantProps & {disabled?: boolean}
|
||||
|
||||
const Context = React.createContext<VariantProps & ButtonState>({
|
||||
|
@ -404,15 +405,7 @@ export function Button({
|
|||
</View>
|
||||
)}
|
||||
<Context.Provider value={context}>
|
||||
{/* @ts-ignore */}
|
||||
{typeof children === 'string' || children?.type === Trans ? (
|
||||
/* @ts-ignore */
|
||||
<ButtonText>{children}</ButtonText>
|
||||
) : typeof children === 'function' ? (
|
||||
children(context)
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
{typeof children === 'function' ? children(context) : children}
|
||||
</Context.Provider>
|
||||
</Pressable>
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@ import {useLingui} from '@lingui/react'
|
|||
import {cleanError} from 'lib/strings/errors'
|
||||
import {CenteredView} from 'view/com/util/Views'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {Error} from '#/components/Error'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
@ -87,7 +87,9 @@ function ListFooterMaybeError({
|
|||
a.py_sm,
|
||||
]}
|
||||
onPress={onRetry}>
|
||||
<Trans>Retry</Trans>
|
||||
<ButtonText>
|
||||
<Trans>Retry</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
@ -244,7 +244,7 @@ function AppealForm({
|
|||
size="medium"
|
||||
onPress={onPressBack}
|
||||
label={_(msg`Back`)}>
|
||||
{_(msg`Back`)}
|
||||
<ButtonText>{_(msg`Back`)}</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
testID="submitBtn"
|
||||
|
@ -253,7 +253,7 @@ function AppealForm({
|
|||
size="medium"
|
||||
onPress={onSubmit}
|
||||
label={_(msg`Submit`)}>
|
||||
{_(msg`Submit`)}
|
||||
<ButtonText>{_(msg`Submit`)}</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
</>
|
||||
|
|
|
@ -10,7 +10,7 @@ import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
|||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {AccountList} from '#/components/AccountList'
|
||||
import {Button} from '#/components/Button'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as TextField from '#/components/forms/TextField'
|
||||
import {FormContainer} from './FormContainer'
|
||||
|
||||
|
@ -75,7 +75,7 @@ export const ChooseAccountForm = ({
|
|||
color="secondary"
|
||||
size="medium"
|
||||
onPress={onPressBack}>
|
||||
{_(msg`Back`)}
|
||||
<ButtonText>{_(msg`Back`)}</ButtonText>
|
||||
</Button>
|
||||
<View style={[a.flex_1]} />
|
||||
</View>
|
||||
|
|
|
@ -237,7 +237,9 @@ export const LoginForm = ({
|
|||
color="secondary"
|
||||
size="medium"
|
||||
onPress={onPressRetryConnect}>
|
||||
{_(msg`Retry`)}
|
||||
<ButtonText>
|
||||
<Trans>Retry</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
) : !serviceDescription ? (
|
||||
<>
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
useTheme,
|
||||
web,
|
||||
} from '#/alf'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
|
||||
import {createPortalGroup} from '#/components/Portal'
|
||||
import {leading, P, Text} from '#/components/Typography'
|
||||
|
@ -73,7 +73,7 @@ export function Layout({children}: React.PropsWithChildren<{}>) {
|
|||
onPress={() => onboardDispatch({type: 'skip'})}
|
||||
// DEV ONLY
|
||||
label="Clear onboarding state">
|
||||
Clear
|
||||
<ButtonText>Clear</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
|
|
|
@ -167,7 +167,7 @@ export function ServerInputDialog({
|
|||
size="small"
|
||||
onPress={() => control.close()}
|
||||
label={_(msg`Done`)}>
|
||||
{_(msg`Done`)}
|
||||
<ButtonText>{_(msg`Done`)}</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
@ -92,7 +92,9 @@ export function ExportCarDialog({
|
|||
size={gtMobile ? 'small' : 'large'}
|
||||
onPress={() => control.close()}
|
||||
label={_(msg`Done`)}>
|
||||
{_(msg`Done`)}
|
||||
<ButtonText>
|
||||
<Trans>Done</Trans>
|
||||
</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
|
|
|
@ -4,15 +4,15 @@ import {View} from 'react-native'
|
|||
import {atoms as a} from '#/alf'
|
||||
import {
|
||||
Button,
|
||||
ButtonVariant,
|
||||
ButtonColor,
|
||||
ButtonIcon,
|
||||
ButtonText,
|
||||
ButtonVariant,
|
||||
} from '#/components/Button'
|
||||
import {H1} from '#/components/Typography'
|
||||
import {ArrowTopRight_Stroke2_Corner0_Rounded as ArrowTopRight} from '#/components/icons/ArrowTopRight'
|
||||
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
|
||||
import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
||||
import {H1} from '#/components/Typography'
|
||||
|
||||
export function Buttons() {
|
||||
return (
|
||||
|
@ -29,7 +29,7 @@ export function Buttons() {
|
|||
color={color as ButtonColor}
|
||||
size="large"
|
||||
label="Click here">
|
||||
Button
|
||||
<ButtonText>Button</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
disabled
|
||||
|
@ -37,7 +37,7 @@ export function Buttons() {
|
|||
color={color as ButtonColor}
|
||||
size="large"
|
||||
label="Click here">
|
||||
Button
|
||||
<ButtonText>Button</ButtonText>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
@ -54,7 +54,7 @@ export function Buttons() {
|
|||
color={name as ButtonColor}
|
||||
size="large"
|
||||
label="Click here">
|
||||
Button
|
||||
<ButtonText>Button</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
disabled
|
||||
|
@ -62,7 +62,7 @@ export function Buttons() {
|
|||
color={name as ButtonColor}
|
||||
size="large"
|
||||
label="Click here">
|
||||
Button
|
||||
<ButtonText>Button</ButtonText>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
),
|
||||
|
@ -77,7 +77,7 @@ export function Buttons() {
|
|||
color={name as ButtonColor}
|
||||
size="large"
|
||||
label="Click here">
|
||||
Button
|
||||
<ButtonText>Button</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
disabled
|
||||
|
@ -85,7 +85,7 @@ export function Buttons() {
|
|||
color={name as ButtonColor}
|
||||
size="large"
|
||||
label="Click here">
|
||||
Button
|
||||
<ButtonText>Button</ButtonText>
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@ import {View} from 'react-native'
|
|||
|
||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {H3, P} from '#/components/Typography'
|
||||
|
@ -26,7 +26,7 @@ export function Dialogs() {
|
|||
basic.open()
|
||||
}}
|
||||
label="Open basic dialog">
|
||||
Open all dialogs
|
||||
<ButtonText>Open all dialogs</ButtonText>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
|
@ -37,7 +37,7 @@ export function Dialogs() {
|
|||
scrollable.open()
|
||||
}}
|
||||
label="Open basic dialog">
|
||||
Open scrollable dialog
|
||||
<ButtonText>Open scrollable dialog</ButtonText>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
|
@ -48,7 +48,7 @@ export function Dialogs() {
|
|||
basic.open()
|
||||
}}
|
||||
label="Open basic dialog">
|
||||
Open basic dialog
|
||||
<ButtonText>Open basic dialog</ButtonText>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
|
@ -57,7 +57,7 @@ export function Dialogs() {
|
|||
size="small"
|
||||
onPress={() => prompt.open()}
|
||||
label="Open prompt">
|
||||
Open prompt
|
||||
<ButtonText>Open prompt</ButtonText>
|
||||
</Button>
|
||||
|
||||
<Prompt.Outer control={prompt}>
|
||||
|
@ -102,7 +102,7 @@ export function Dialogs() {
|
|||
size="small"
|
||||
onPress={closeAllDialogs}
|
||||
label="Close all dialogs">
|
||||
Close all dialogs
|
||||
<ButtonText>Close all dialogs</ButtonText>
|
||||
</Button>
|
||||
<View style={{height: 1000}} />
|
||||
<View style={[a.flex_row, a.justify_end]}>
|
||||
|
@ -116,7 +116,7 @@ export function Dialogs() {
|
|||
})
|
||||
}
|
||||
label="Open basic dialog">
|
||||
Close dialog
|
||||
<ButtonText>Close dialog</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||
import {View} from 'react-native'
|
||||
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {DateField, LabelText} from '#/components/forms/DateField'
|
||||
import * as TextField from '#/components/forms/TextField'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
|
@ -191,7 +191,7 @@ export function Forms() {
|
|||
setToggleGroupBValues(['a', 'b'])
|
||||
setToggleGroupCValues(['a'])
|
||||
}}>
|
||||
Reset all toggles
|
||||
<ButtonText>Reset all toggles</ButtonText>
|
||||
</Button>
|
||||
|
||||
<View style={[a.gap_md, a.align_start, a.w_full]}>
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
||||
|
||||
import {atoms as a, useTheme, ThemeProvider} from '#/alf'
|
||||
import {useSetThemePrefs} from '#/state/shell'
|
||||
import {Button} from '#/components/Button'
|
||||
|
||||
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
||||
import {atoms as a, ThemeProvider, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {Breakpoints} from './Breakpoints'
|
||||
import {Buttons} from './Buttons'
|
||||
import {Dialogs} from './Dialogs'
|
||||
import {Forms} from './Forms'
|
||||
import {Icons} from './Icons'
|
||||
import {Links} from './Links'
|
||||
import {Menus} from './Menus'
|
||||
import {Shadows} from './Shadows'
|
||||
import {Spacing} from './Spacing'
|
||||
import {Theming} from './Theming'
|
||||
import {Typography} from './Typography'
|
||||
import {Spacing} from './Spacing'
|
||||
import {Buttons} from './Buttons'
|
||||
import {Links} from './Links'
|
||||
import {Forms} from './Forms'
|
||||
import {Dialogs} from './Dialogs'
|
||||
import {Breakpoints} from './Breakpoints'
|
||||
import {Shadows} from './Shadows'
|
||||
import {Icons} from './Icons'
|
||||
import {Menus} from './Menus'
|
||||
|
||||
export function Storybook() {
|
||||
const t = useTheme()
|
||||
|
@ -33,7 +32,7 @@ export function Storybook() {
|
|||
size="small"
|
||||
label='Set theme to "system"'
|
||||
onPress={() => setColorMode('system')}>
|
||||
System
|
||||
<ButtonText>System</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
variant="solid"
|
||||
|
@ -41,7 +40,7 @@ export function Storybook() {
|
|||
size="small"
|
||||
label='Set theme to "light"'
|
||||
onPress={() => setColorMode('light')}>
|
||||
Light
|
||||
<ButtonText>Light</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
variant="solid"
|
||||
|
@ -52,7 +51,7 @@ export function Storybook() {
|
|||
setColorMode('dark')
|
||||
setDarkTheme('dim')
|
||||
}}>
|
||||
Dim
|
||||
<ButtonText>Dim</ButtonText>
|
||||
</Button>
|
||||
<Button
|
||||
variant="solid"
|
||||
|
@ -63,7 +62,7 @@ export function Storybook() {
|
|||
setColorMode('dark')
|
||||
setDarkTheme('dark')
|
||||
}}>
|
||||
Dark
|
||||
<ButtonText>Dark</ButtonText>
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue