diff options
-rw-r--r-- | .eslintrc.js | 15 | ||||
-rw-r--r-- | eslint/__tests__/avoid-unwrapped-text.test.js | 339 | ||||
-rw-r--r-- | eslint/avoid-unwrapped-text.js | 194 | ||||
-rw-r--r-- | src/components/Button.tsx | 21 | ||||
-rw-r--r-- | src/components/Lists.tsx | 6 | ||||
-rw-r--r-- | src/components/moderation/LabelsOnMeDialog.tsx | 4 | ||||
-rw-r--r-- | src/screens/Login/ChooseAccountForm.tsx | 4 | ||||
-rw-r--r-- | src/screens/Login/LoginForm.tsx | 4 | ||||
-rw-r--r-- | src/screens/Onboarding/Layout.tsx | 4 | ||||
-rw-r--r-- | src/view/com/auth/server-input/index.tsx | 2 | ||||
-rw-r--r-- | src/view/screens/Settings/ExportCarDialog.tsx | 4 | ||||
-rw-r--r-- | src/view/screens/Storybook/Buttons.tsx | 16 | ||||
-rw-r--r-- | src/view/screens/Storybook/Dialogs.tsx | 14 | ||||
-rw-r--r-- | src/view/screens/Storybook/Forms.tsx | 4 | ||||
-rw-r--r-- | src/view/screens/Storybook/index.tsx | 29 |
15 files changed, 587 insertions, 73 deletions
diff --git a/.eslintrc.js b/.eslintrc.js index df0c76230..a999fd24b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,17 +23,12 @@ module.exports = { 'bsky-internal/avoid-unwrapped-text': [ 'error', { - impliedTextComponents: [ - 'Button', // TODO: Not always safe. - 'H1', - 'H2', - 'H3', - 'H4', - 'H5', - 'H6', - 'P', - ], + impliedTextComponents: ['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P'], impliedTextProps: [], + suggestedTextWrappers: { + Button: 'ButtonText', + 'ToggleButton.Button': 'ToggleButton.ButtonText', + }, }, ], 'simple-import-sort/imports': [ diff --git a/eslint/__tests__/avoid-unwrapped-text.test.js b/eslint/__tests__/avoid-unwrapped-text.test.js index 7c667b4a8..a6762b8fd 100644 --- a/eslint/__tests__/avoid-unwrapped-text.test.js +++ b/eslint/__tests__/avoid-unwrapped-text.test.js @@ -199,7 +199,7 @@ describe('avoid-unwrapped-text', () => { { code: ` -<View prop={ +<View propText={ <Trans><Text>foo</Text></Trans> }> <Bar /> @@ -281,6 +281,170 @@ function MyText({ foo }) { } `, }, + + { + code: ` +<View> + <Text>{'foo'}</Text> +</View> + `, + }, + + { + code: ` +<View> + <Text>{foo + 'foo'}</Text> +</View> + `, + }, + + { + code: ` +<View> + <Text><Trans>{'foo'}</Trans></Text> +</View> + `, + }, + + { + code: ` +<View> + {foo['bar'] && <Bar />} +</View> + `, + }, + + { + code: ` +<View> + {(foo === 'bar') && <Bar />} +</View> + `, + }, + + { + code: ` +<View> + {(foo !== 'bar') && <Bar />} +</View> + `, + }, + + { + code: ` +<View> + <Text>{\`foo\`}</Text> +</View> + `, + }, + + { + code: ` +<View> + <Text><Trans>{\`foo\`}</Trans></Text> +</View> + `, + }, + + { + code: ` +<View> + <Text>{_(msg\`foo\`)}</Text> +</View> + `, + }, + + { + code: ` +<View> + <Text><Trans>{_(msg\`foo\`)}</Trans></Text> +</View> + `, + }, + + { + code: ` +<Foo> + <View prop={stuff('foo')}> + <Bar /> + </View> +</Foo> + `, + }, + + { + code: ` +<Foo> + <View onClick={() => stuff('foo')}> + <Bar /> + </View> +</Foo> + `, + }, + + { + code: ` +<View> + {renderItem('foo')} +</View> + `, + }, + + { + code: ` +<View> + {foo === 'foo' && <Bar />} +</View> + `, + }, + + { + code: ` +<View> + {foo['foo'] && <Bar />} +</View> + `, + }, + + { + code: ` +<View> + {check('foo') && <Bar />} +</View> + `, + }, + + { + code: ` +<View> + {foo.bar && <Bar />} +</View> + `, + }, + + { + code: ` +<Text> + <Trans>{renderItem('foo')}</Trans> +</Text> + `, + }, + + { + code: ` +<View> + {null} +</View> + `, + }, + + { + code: ` +<Text> + <Trans>{null}</Trans> +</Text> + `, + }, ], invalid: [ @@ -455,6 +619,179 @@ function MyText({ foo }) { `, errors: 1, }, + + { + code: ` +<View> + {'foo'} +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + {foo && 'foo'} +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{'foo'}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + {foo && <Trans>{'foo'}</Trans>} +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + {10} +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{10}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{foo + 10}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + {\`foo\`} +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{\`foo\`}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{foo + \`foo\`}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + {_(msg\`foo\`)} +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + {foo + _(msg\`foo\`)} +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{_(msg\`foo\`)}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{foo + _(msg\`foo\`)}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>foo</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans><Trans>foo</Trans></Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{foo}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View> + <Trans>{'foo'}</Trans> +</View> + `, + errors: 1, + }, + + { + code: ` +<View prop={ + <Trans><Text>foo</Text></Trans> +}> + <Bar /> +</View> + `, + errors: 1, + }, ], } diff --git a/eslint/avoid-unwrapped-text.js b/eslint/avoid-unwrapped-text.js index 79d099f00..eef31f795 100644 --- a/eslint/avoid-unwrapped-text.js +++ b/eslint/avoid-unwrapped-text.js @@ -33,6 +33,7 @@ exports.create = function create(context) { const options = context.options[0] || {} const impliedTextProps = options.impliedTextProps ?? [] const impliedTextComponents = options.impliedTextComponents ?? [] + const suggestedTextWrappers = options.suggestedTextWrappers ?? {} const textProps = [...impliedTextProps] const textComponents = ['Text', ...impliedTextComponents] @@ -54,13 +55,13 @@ exports.create = function create(context) { return } if (tagName === 'Trans') { - // Skip over it and check above. + // Exit and rely on the traversal for <Trans> JSXElement (code below). // TODO: Maybe validate that it's present. - parent = parent.parent - continue + return } - let message = 'Wrap this string in <Text>.' - if (tagName !== 'View') { + const suggestedWrapper = suggestedTextWrappers[tagName] + let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` + if (tagName !== 'View' && !suggestedWrapper) { message += ' If <' + tagName + @@ -112,6 +113,189 @@ exports.create = function create(context) { continue } }, + Literal(node) { + if (typeof node.value !== 'string' && typeof node.value !== 'number') { + return + } + let parent = node.parent + while (parent) { + if (parent.type === 'JSXElement') { + const tagName = getTagName(parent) + if (isTextComponent(tagName)) { + // We're good. + return + } + if (tagName === 'Trans') { + // Exit and rely on the traversal for <Trans> JSXElement (code below). + // TODO: Maybe validate that it's present. + return + } + const suggestedWrapper = suggestedTextWrappers[tagName] + let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` + if (tagName !== 'View' && !suggestedWrapper) { + message += + ' If <' + + tagName + + '> is guaranteed to render <Text>, ' + + 'rename it to <' + + tagName + + 'Text> or add it to impliedTextComponents.' + } + context.report({ + node, + message, + }) + return + } + + if (parent.type === 'BinaryExpression' && parent.operator === '+') { + parent = parent.parent + continue + } + + if ( + parent.type === 'JSXExpressionContainer' || + parent.type === 'LogicalExpression' + ) { + parent = parent.parent + continue + } + + // Be conservative for other types. + return + } + }, + TemplateLiteral(node) { + let parent = node.parent + while (parent) { + if (parent.type === 'JSXElement') { + const tagName = getTagName(parent) + if (isTextComponent(tagName)) { + // We're good. + return + } + if (tagName === 'Trans') { + // Exit and rely on the traversal for <Trans> JSXElement (code below). + // TODO: Maybe validate that it's present. + return + } + const suggestedWrapper = suggestedTextWrappers[tagName] + let message = `Wrap this string in <${suggestedWrapper ?? 'Text'}>.` + if (tagName !== 'View' && !suggestedWrapper) { + message += + ' If <' + + tagName + + '> is guaranteed to render <Text>, ' + + 'rename it to <' + + tagName + + 'Text> or add it to impliedTextComponents.' + } + context.report({ + node, + message, + }) + return + } + + if ( + parent.type === 'CallExpression' && + parent.callee.type === 'Identifier' && + parent.callee.name === '_' + ) { + // This is a user-facing string, keep going up. + parent = parent.parent + continue + } + + if (parent.type === 'BinaryExpression' && parent.operator === '+') { + parent = parent.parent + continue + } + + if ( + parent.type === 'JSXExpressionContainer' || + parent.type === 'LogicalExpression' || + parent.type === 'TaggedTemplateExpression' + ) { + parent = parent.parent + continue + } + + // Be conservative for other types. + return + } + }, + JSXElement(node) { + if (getTagName(node) !== 'Trans') { + return + } + let parent = node.parent + while (parent) { + if (parent.type === 'JSXElement') { + const tagName = getTagName(parent) + if (isTextComponent(tagName)) { + // We're good. + return + } + if (tagName === 'Trans') { + // Exit and rely on the traversal for this JSXElement. + // TODO: Should nested <Trans> even be allowed? + return + } + const suggestedWrapper = suggestedTextWrappers[tagName] + let message = `Wrap this <Trans> in <${suggestedWrapper ?? 'Text'}>.` + if (tagName !== 'View' && !suggestedWrapper) { + message += + ' If <' + + tagName + + '> is guaranteed to render <Text>, ' + + 'rename it to <' + + tagName + + 'Text> or add it to impliedTextComponents.' + } + context.report({ + node, + message, + }) + return + } + + if ( + parent.type === 'JSXAttribute' && + parent.name.type === 'JSXIdentifier' && + parent.parent.type === 'JSXOpeningElement' && + parent.parent.parent.type === 'JSXElement' + ) { + const tagName = getTagName(parent.parent.parent) + const propName = parent.name.name + if ( + textProps.includes(tagName + ' ' + propName) || + propName === 'text' || + propName.endsWith('Text') + ) { + // We're good. + return + } + const message = + 'Wrap this <Trans> in <Text>.' + + ' If `' + + propName + + '` is guaranteed to be wrapped in <Text>, ' + + 'rename it to `' + + propName + + 'Text' + + '` or add it to impliedTextProps.' + context.report({ + node, + message, + }) + return + } + + parent = parent.parent + continue + } + }, ReturnStatement(node) { let fnScope = context.getScope() while (fnScope && fnScope.type !== 'function') { diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 12b3fe4cb..33d777971 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -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> ) diff --git a/src/components/Lists.tsx b/src/components/Lists.tsx index 605626fef..89913b12b 100644 --- a/src/components/Lists.tsx +++ b/src/components/Lists.tsx @@ -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> diff --git a/src/components/moderation/LabelsOnMeDialog.tsx b/src/components/moderation/LabelsOnMeDialog.tsx index 95e3d242b..5cf86644c 100644 --- a/src/components/moderation/LabelsOnMeDialog.tsx +++ b/src/components/moderation/LabelsOnMeDialog.tsx @@ -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> </> diff --git a/src/screens/Login/ChooseAccountForm.tsx b/src/screens/Login/ChooseAccountForm.tsx index 01eca1876..134411903 100644 --- a/src/screens/Login/ChooseAccountForm.tsx +++ b/src/screens/Login/ChooseAccountForm.tsx @@ -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> diff --git a/src/screens/Login/LoginForm.tsx b/src/screens/Login/LoginForm.tsx index 6b1340b95..debb39bed 100644 --- a/src/screens/Login/LoginForm.tsx +++ b/src/screens/Login/LoginForm.tsx @@ -237,7 +237,9 @@ export const LoginForm = ({ color="secondary" size="medium" onPress={onPressRetryConnect}> - {_(msg`Retry`)} + <ButtonText> + <Trans>Retry</Trans> + </ButtonText> </Button> ) : !serviceDescription ? ( <> diff --git a/src/screens/Onboarding/Layout.tsx b/src/screens/Onboarding/Layout.tsx index cfaf20ffe..d48234cca 100644 --- a/src/screens/Onboarding/Layout.tsx +++ b/src/screens/Onboarding/Layout.tsx @@ -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> )} diff --git a/src/view/com/auth/server-input/index.tsx b/src/view/com/auth/server-input/index.tsx index 2380fffe2..0d64650dd 100644 --- a/src/view/com/auth/server-input/index.tsx +++ b/src/view/com/auth/server-input/index.tsx @@ -167,7 +167,7 @@ export function ServerInputDialog({ size="small" onPress={() => control.close()} label={_(msg`Done`)}> - {_(msg`Done`)} + <ButtonText>{_(msg`Done`)}</ButtonText> </Button> </View> </View> diff --git a/src/view/screens/Settings/ExportCarDialog.tsx b/src/view/screens/Settings/ExportCarDialog.tsx index 3ec37e85e..e901fb090 100644 --- a/src/view/screens/Settings/ExportCarDialog.tsx +++ b/src/view/screens/Settings/ExportCarDialog.tsx @@ -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> diff --git a/src/view/screens/Storybook/Buttons.tsx b/src/view/screens/Storybook/Buttons.tsx index ad2fff3f4..cae8ec314 100644 --- a/src/view/screens/Storybook/Buttons.tsx +++ b/src/view/screens/Storybook/Buttons.tsx @@ -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> ), diff --git a/src/view/screens/Storybook/Dialogs.tsx b/src/view/screens/Storybook/Dialogs.tsx index 5c5e480fe..4722784ca 100644 --- a/src/view/screens/Storybook/Dialogs.tsx +++ b/src/view/screens/Storybook/Dialogs.tsx @@ -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> diff --git a/src/view/screens/Storybook/Forms.tsx b/src/view/screens/Storybook/Forms.tsx index b771ad5e0..1e4efdcc7 100644 --- a/src/view/screens/Storybook/Forms.tsx +++ b/src/view/screens/Storybook/Forms.tsx @@ -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]}> diff --git a/src/view/screens/Storybook/index.tsx b/src/view/screens/Storybook/index.tsx index 3a2e2f369..35a666601 100644 --- a/src/view/screens/Storybook/index.tsx +++ b/src/view/screens/Storybook/index.tsx @@ -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 {Theming} from './Theming' -import {Typography} from './Typography' -import {Spacing} from './Spacing' +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 {Links} from './Links' -import {Forms} from './Forms' import {Dialogs} from './Dialogs' -import {Breakpoints} from './Breakpoints' -import {Shadows} from './Shadows' +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' 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> |