diff options
Diffstat (limited to 'src/view/com/auth')
-rw-r--r-- | src/view/com/auth/SplashScreen.tsx | 10 | ||||
-rw-r--r-- | src/view/com/auth/SplashScreen.web.tsx | 13 | ||||
-rw-r--r-- | src/view/com/auth/create/CreateAccount.tsx | 20 | ||||
-rw-r--r-- | src/view/com/auth/create/Step1.tsx | 14 | ||||
-rw-r--r-- | src/view/com/auth/create/Step2.tsx | 33 | ||||
-rw-r--r-- | src/view/com/auth/create/Step3.tsx | 3 | ||||
-rw-r--r-- | src/view/com/auth/login/Login.tsx | 100 | ||||
-rw-r--r-- | src/view/com/auth/util/TextInput.tsx | 25 |
8 files changed, 169 insertions, 49 deletions
diff --git a/src/view/com/auth/SplashScreen.tsx b/src/view/com/auth/SplashScreen.tsx index f98bed120..41787bb5f 100644 --- a/src/view/com/auth/SplashScreen.tsx +++ b/src/view/com/auth/SplashScreen.tsx @@ -28,7 +28,10 @@ export const SplashScreen = ({ <TouchableOpacity testID="createAccountButton" style={[styles.btn, {backgroundColor: colors.blue3}]} - onPress={onPressCreateAccount}> + onPress={onPressCreateAccount} + accessibilityRole="button" + accessibilityLabel="Create new account" + accessibilityHint="Opens flow to create a new Bluesky account"> <Text style={[s.white, styles.btnLabel]}> Create a new account </Text> @@ -36,7 +39,10 @@ export const SplashScreen = ({ <TouchableOpacity testID="signInButton" style={[styles.btn, pal.btn]} - onPress={onPressSignin}> + onPress={onPressSignin} + accessibilityRole="button" + accessibilityLabel="Sign in" + accessibilityHint="Opens flow to sign into your existing Bluesky account"> <Text style={[pal.text, styles.btnLabel]}>Sign in</Text> </TouchableOpacity> </View> diff --git a/src/view/com/auth/SplashScreen.web.tsx b/src/view/com/auth/SplashScreen.web.tsx index 7fac5a8c0..9236968c4 100644 --- a/src/view/com/auth/SplashScreen.web.tsx +++ b/src/view/com/auth/SplashScreen.web.tsx @@ -43,7 +43,9 @@ export const SplashScreen = ({ <TouchableOpacity testID="createAccountButton" style={[styles.btn, {backgroundColor: colors.blue3}]} - onPress={onPressCreateAccount}> + onPress={onPressCreateAccount} + // TODO: web accessibility + accessibilityRole="button"> <Text style={[s.white, styles.btnLabel]}> Create a new account </Text> @@ -51,7 +53,9 @@ export const SplashScreen = ({ <TouchableOpacity testID="signInButton" style={[styles.btn, pal.btn]} - onPress={onPressSignin}> + onPress={onPressSignin} + // TODO: web accessibility + accessibilityRole="button"> <Text style={[pal.text, styles.btnLabel]}>Sign in</Text> </TouchableOpacity> </View> @@ -60,7 +64,10 @@ export const SplashScreen = ({ style={[styles.notice, pal.textLight]} lineHeight={1.3}> Bluesky will launch soon.{' '} - <TouchableOpacity onPress={onPressWaitlist}> + <TouchableOpacity + onPress={onPressWaitlist} + // TODO: web accessibility + accessibilityRole="button"> <Text type="xl" style={pal.link}> Join the waitlist </Text> diff --git a/src/view/com/auth/create/CreateAccount.tsx b/src/view/com/auth/create/CreateAccount.tsx index 467b87948..ac03081df 100644 --- a/src/view/com/auth/create/CreateAccount.tsx +++ b/src/view/com/auth/create/CreateAccount.tsx @@ -72,14 +72,24 @@ export const CreateAccount = observer( {model.step === 3 && <Step3 model={model} />} </View> <View style={[s.flexRow, s.pl20, s.pr20]}> - <TouchableOpacity onPress={onPressBackInner} testID="backBtn"> + <TouchableOpacity + onPress={onPressBackInner} + testID="backBtn" + accessibilityRole="button" + accessibilityLabel="Go back" + accessibilityHint="Navigates to the previous screen"> <Text type="xl" style={pal.link}> Back </Text> </TouchableOpacity> <View style={s.flex1} /> {model.canNext ? ( - <TouchableOpacity testID="nextBtn" onPress={onPressNext}> + <TouchableOpacity + testID="nextBtn" + onPress={onPressNext} + accessibilityRole="button" + accessibilityLabel="Go to next" + accessibilityHint="Navigates to the next screen"> {model.isProcessing ? ( <ActivityIndicator /> ) : ( @@ -91,7 +101,11 @@ export const CreateAccount = observer( ) : model.didServiceDescriptionFetchFail ? ( <TouchableOpacity testID="retryConnectBtn" - onPress={onPressRetryConnect}> + onPress={onPressRetryConnect} + accessibilityRole="button" + accessibilityLabel="Retry" + accessibilityHint="Retries account creation" + accessibilityLiveRegion="polite"> <Text type="xl-bold" style={[pal.link, s.pr5]}> Retry </Text> diff --git a/src/view/com/auth/create/Step1.tsx b/src/view/com/auth/create/Step1.tsx index ca964ede2..ac0d706d7 100644 --- a/src/view/com/auth/create/Step1.tsx +++ b/src/view/com/auth/create/Step1.tsx @@ -57,7 +57,7 @@ export const Step1 = observer(({model}: {model: CreateAccountModel}) => { <View> <StepHeader step="1" title="Your hosting provider" /> <Text style={[pal.text, s.mb10]}> - This is the company that keeps you online. + This is the service that keeps you online. </Text> <Option testID="blueskyServerBtn" @@ -72,7 +72,7 @@ export const Step1 = observer(({model}: {model: CreateAccountModel}) => { label="Other" onPress={onPressOther}> <View style={styles.otherForm}> - <Text style={[pal.text, s.mb5]}> + <Text nativeID="addressProvider" style={[pal.text, s.mb5]}> Enter the address of your provider: </Text> <TextInput @@ -82,6 +82,9 @@ export const Step1 = observer(({model}: {model: CreateAccountModel}) => { value={model.serviceUrl} editable onChange={onChangeServiceUrl} + accessibilityHint="Input hosting provider address" + accessibilityLabel="Hosting provider address" + accessibilityLabelledBy="addressProvider" /> {LOGIN_INCLUDE_DEV_SERVERS && ( <View style={[s.flexRow, s.mt10]}> @@ -136,7 +139,12 @@ function Option({ return ( <View style={[styles.option, pal.border]}> - <TouchableWithoutFeedback onPress={onPress} testID={testID}> + <TouchableWithoutFeedback + onPress={onPress} + testID={testID} + accessibilityRole="button" + accessibilityLabel={label} + accessibilityHint={`Sets hosting provider to ${label}`}> <View style={styles.optionHeading}> <View style={[styles.circle, pal.border]}> {isSelected ? ( diff --git a/src/view/com/auth/create/Step2.tsx b/src/view/com/auth/create/Step2.tsx index 375f80796..eceee50d3 100644 --- a/src/view/com/auth/create/Step2.tsx +++ b/src/view/com/auth/create/Step2.tsx @@ -41,6 +41,9 @@ export const Step2 = observer(({model}: {model: CreateAccountModel}) => { value={model.inviteCode} editable onChange={model.setInviteCode} + accessibilityRole="button" + accessibilityLabel="Invite code" + accessibilityHint="Input invite code to proceed" /> </View> )} @@ -48,7 +51,11 @@ export const Step2 = observer(({model}: {model: CreateAccountModel}) => { {!model.inviteCode && model.isInviteCodeRequired ? ( <Text style={[s.alignBaseline, pal.text]}> Don't have an invite code?{' '} - <TouchableWithoutFeedback onPress={onPressWaitlist}> + <TouchableWithoutFeedback + onPress={onPressWaitlist} + accessibilityRole="button" + accessibilityLabel="Waitlist" + accessibilityHint="Opens Bluesky waitlist form"> <Text style={pal.link}>Join the waitlist</Text> </TouchableWithoutFeedback>{' '} to try the beta before it's publicly available. @@ -56,7 +63,7 @@ export const Step2 = observer(({model}: {model: CreateAccountModel}) => { ) : ( <> <View style={s.pb20}> - <Text type="md-medium" style={[pal.text, s.mb2]}> + <Text type="md-medium" style={[pal.text, s.mb2]} nativeID="email"> Email address </Text> <TextInput @@ -66,11 +73,17 @@ export const Step2 = observer(({model}: {model: CreateAccountModel}) => { value={model.email} editable onChange={model.setEmail} + accessibilityLabel="Email" + accessibilityHint="Input email for Bluesky waitlist" + accessibilityLabelledBy="email" /> </View> <View style={s.pb20}> - <Text type="md-medium" style={[pal.text, s.mb2]}> + <Text + type="md-medium" + style={[pal.text, s.mb2]} + nativeID="password"> Password </Text> <TextInput @@ -81,17 +94,27 @@ export const Step2 = observer(({model}: {model: CreateAccountModel}) => { editable secureTextEntry onChange={model.setPassword} + accessibilityLabel="Password" + accessibilityHint="Set password" + accessibilityLabelledBy="password" /> </View> <View style={s.pb20}> - <Text type="md-medium" style={[pal.text, s.mb2]}> + <Text + type="md-medium" + style={[pal.text, s.mb2]} + nativeID="legalCheck"> Legal check </Text> <TouchableOpacity testID="is13Input" style={[styles.toggleBtn, pal.border]} - onPress={() => model.setIs13(!model.is13)}> + onPress={() => model.setIs13(!model.is13)} + accessibilityRole="checkbox" + accessibilityLabel="Verify age" + accessibilityHint="Verifies that I am at least 13 years of age" + accessibilityLabelledBy="legalCheck"> <View style={[pal.borderDark, styles.checkbox]}> {model.is13 && ( <FontAwesomeIcon icon="check" style={s.blue3} size={16} /> diff --git a/src/view/com/auth/create/Step3.tsx b/src/view/com/auth/create/Step3.tsx index 13ab39a10..3d9d47628 100644 --- a/src/view/com/auth/create/Step3.tsx +++ b/src/view/com/auth/create/Step3.tsx @@ -23,6 +23,9 @@ export const Step3 = observer(({model}: {model: CreateAccountModel}) => { value={model.handle} editable onChange={model.setHandle} + // TODO: Add explicit text label + accessibilityLabel="User handle" + accessibilityHint="Input your user handle" /> <Text type="lg" style={[pal.text, s.pl5, s.pt10]}> Your full handle will be{' '} diff --git a/src/view/com/auth/login/Login.tsx b/src/view/com/auth/login/Login.tsx index eff1642f0..37558fb54 100644 --- a/src/view/com/auth/login/Login.tsx +++ b/src/view/com/auth/login/Login.tsx @@ -195,7 +195,10 @@ const ChooseAccountForm = ({ testID={`chooseAccountBtn-${account.handle}`} key={account.did} style={[pal.view, pal.border, styles.account]} - onPress={() => onTryAccount(account)}> + onPress={() => onTryAccount(account)} + accessibilityRole="button" + accessibilityLabel={`Sign in as ${account.handle}`} + accessibilityHint="Double tap to sign in"> <View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}> <View style={s.p10}> @@ -220,7 +223,10 @@ const ChooseAccountForm = ({ <TouchableOpacity testID="chooseNewAccountBtn" style={[pal.view, pal.border, styles.account, styles.accountLast]} - onPress={() => onSelectAccount(undefined)}> + onPress={() => onSelectAccount(undefined)} + accessibilityRole="button" + accessibilityLabel="Login to account that is not listed" + accessibilityHint=""> <View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}> <Text style={[styles.accountText, styles.accountTextOther]}> <Text type="lg" style={pal.text}> @@ -235,7 +241,11 @@ const ChooseAccountForm = ({ </View> </TouchableOpacity> <View style={[s.flexRow, s.alignCenter, s.pl20, s.pr20]}> - <TouchableOpacity onPress={onPressBack}> + <TouchableOpacity + onPress={onPressBack} + accessibilityRole="button" + accessibilityLabel="Go back" + accessibilityHint="Navigates to the previous screen"> <Text type="xl" style={[pal.link, s.pl5]}> Back </Text> @@ -351,7 +361,10 @@ const LoginForm = ({ <TouchableOpacity testID="loginSelectServiceButton" style={styles.textBtn} - onPress={onPressSelectService}> + onPress={onPressSelectService} + accessibilityRole="button" + accessibilityLabel="Select service" + accessibilityHint="Sets server for the Bluesky client"> <Text type="xl" style={[pal.text, styles.textBtnLabel]}> {toNiceDomain(serviceUrl)} </Text> @@ -386,6 +399,8 @@ const LoginForm = ({ value={identifier} onChangeText={str => setIdentifier((str || '').toLowerCase())} editable={!isProcessing} + accessibilityLabel="Username or email address" + accessibilityHint="Input the username or email address you used at signup" /> </View> <View style={[pal.borderDark, styles.groupContent]}> @@ -402,14 +417,28 @@ const LoginForm = ({ autoCorrect={false} keyboardAppearance={theme.colorScheme} secureTextEntry + // HACK + // mitigates a known issue where the secure password prompt interferes + // https://github.com/facebook/react-native/issues/21911 + // prf + textContentType="oneTimeCode" value={password} onChangeText={setPassword} editable={!isProcessing} + accessibilityLabel="Password" + accessibilityHint={ + identifier === '' + ? 'Input your password' + : `Input the password tied to ${identifier}` + } /> <TouchableOpacity testID="forgotPasswordButton" style={styles.textInputInnerBtn} - onPress={onPressForgotPassword}> + onPress={onPressForgotPassword} + accessibilityRole="button" + accessibilityLabel="Forgot password" + accessibilityHint="Opens password reset form"> <Text style={pal.link}>Forgot</Text> </TouchableOpacity> </View> @@ -425,7 +454,11 @@ const LoginForm = ({ </View> ) : undefined} <View style={[s.flexRow, s.alignCenter, s.pl20, s.pr20]}> - <TouchableOpacity onPress={onPressBack}> + <TouchableOpacity + onPress={onPressBack} + accessibilityRole="button" + accessibilityLabel="Go back" + accessibilityHint="Navigates to the previous screen"> <Text type="xl" style={[pal.link, s.pl5]}> Back </Text> @@ -434,7 +467,10 @@ const LoginForm = ({ {!serviceDescription && error ? ( <TouchableOpacity testID="loginRetryButton" - onPress={onPressRetryConnect}> + onPress={onPressRetryConnect} + accessibilityRole="button" + accessibilityLabel="Retry" + accessibilityHint="Retries login"> <Text type="xl-bold" style={[pal.link, s.pr5]}> Retry </Text> @@ -449,7 +485,12 @@ const LoginForm = ({ ) : isProcessing ? ( <ActivityIndicator /> ) : isReady ? ( - <TouchableOpacity testID="loginNextButton" onPress={onPressNext}> + <TouchableOpacity + testID="loginNextButton" + onPress={onPressNext} + accessibilityRole="button" + accessibilityLabel="Go to next" + accessibilityHint="Navigates to the next screen"> <Text type="xl-bold" style={[pal.link, s.pr5]}> Next </Text> @@ -539,7 +580,10 @@ const ForgotPasswordForm = ({ <TouchableOpacity testID="forgotPasswordSelectServiceButton" style={[pal.borderDark, styles.groupContent, styles.noTopBorder]} - onPress={onPressSelectService}> + onPress={onPressSelectService} + accessibilityRole="button" + accessibilityLabel="Hosting provider" + accessibilityHint="Sets hosting provider for password reset"> <FontAwesomeIcon icon="globe" style={[pal.textLight, styles.groupContentIcon]} @@ -572,6 +616,8 @@ const ForgotPasswordForm = ({ value={email} onChangeText={setEmail} editable={!isProcessing} + accessibilityLabel="Email" + accessibilityHint="Sets email for password reset" /> </View> </View> @@ -586,7 +632,11 @@ const ForgotPasswordForm = ({ </View> ) : undefined} <View style={[s.flexRow, s.alignCenter, s.pl20, s.pr20]}> - <TouchableOpacity onPress={onPressBack}> + <TouchableOpacity + onPress={onPressBack} + accessibilityRole="button" + accessibilityLabel="Go back" + accessibilityHint="Navigates to the previous screen"> <Text type="xl" style={[pal.link, s.pl5]}> Back </Text> @@ -599,7 +649,12 @@ const ForgotPasswordForm = ({ Next </Text> ) : ( - <TouchableOpacity testID="newPasswordButton" onPress={onPressNext}> + <TouchableOpacity + testID="newPasswordButton" + onPress={onPressNext} + accessibilityRole="button" + accessibilityLabel="Go to next" + accessibilityHint="Navigates to the next screen"> <Text type="xl-bold" style={[pal.link, s.pr5]}> Next </Text> @@ -699,6 +754,9 @@ const SetNewPasswordForm = ({ value={resetCode} onChangeText={setResetCode} editable={!isProcessing} + accessible={true} + accessibilityLabel="Reset code" + accessibilityHint="Input code sent to your email for password reset" /> </View> <View style={[pal.borderDark, styles.groupContent]}> @@ -718,6 +776,9 @@ const SetNewPasswordForm = ({ value={password} onChangeText={setPassword} editable={!isProcessing} + accessible={true} + accessibilityLabel="Password" + accessibilityHint="Input new password" /> </View> </View> @@ -732,7 +793,11 @@ const SetNewPasswordForm = ({ </View> ) : undefined} <View style={[s.flexRow, s.alignCenter, s.pl20, s.pr20]}> - <TouchableOpacity onPress={onPressBack}> + <TouchableOpacity + onPress={onPressBack} + accessibilityRole="button" + accessibilityLabel="Go back" + accessibilityHint="Navigates to the previous screen"> <Text type="xl" style={[pal.link, s.pl5]}> Back </Text> @@ -747,7 +812,10 @@ const SetNewPasswordForm = ({ ) : ( <TouchableOpacity testID="setNewPasswordButton" - onPress={onPressNext}> + onPress={onPressNext} + accessibilityRole="button" + accessibilityLabel="Go to next" + accessibilityHint="Navigates to the next screen"> <Text type="xl-bold" style={[pal.link, s.pr5]}> Next </Text> @@ -783,7 +851,11 @@ const PasswordUpdatedForm = ({onPressNext}: {onPressNext: () => void}) => { </Text> <View style={[s.flexRow, s.alignCenter, s.pl20, s.pr20]}> <View style={s.flex1} /> - <TouchableOpacity onPress={onPressNext}> + <TouchableOpacity + onPress={onPressNext} + accessibilityRole="button" + accessibilityLabel="Close alert" + accessibilityHint="Closes password update alert"> <Text type="xl-bold" style={[pal.link, s.pr5]}> Okay </Text> diff --git a/src/view/com/auth/util/TextInput.tsx b/src/view/com/auth/util/TextInput.tsx index 934bf2acf..38aff0384 100644 --- a/src/view/com/auth/util/TextInput.tsx +++ b/src/view/com/auth/util/TextInput.tsx @@ -1,27 +1,17 @@ -import React from 'react' +import React, {ComponentProps} from 'react' import {StyleSheet, TextInput as RNTextInput, View} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {IconProp} from '@fortawesome/fontawesome-svg-core' import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' -export function TextInput({ - testID, - icon, - value, - placeholder, - editable, - secureTextEntry, - onChange, -}: { +interface Props extends Omit<ComponentProps<typeof RNTextInput>, 'onChange'> { testID?: string icon: IconProp - value: string - placeholder: string - editable: boolean - secureTextEntry?: boolean onChange: (v: string) => void -}) { +} + +export function TextInput({testID, icon, onChange, ...props}: Props) { const theme = useTheme() const pal = usePalette('default') return ( @@ -30,15 +20,12 @@ export function TextInput({ <RNTextInput testID={testID} style={[pal.text, styles.textInput]} - placeholder={placeholder} placeholderTextColor={pal.colors.textLight} autoCapitalize="none" autoCorrect={false} keyboardAppearance={theme.colorScheme} - secureTextEntry={secureTextEntry} - value={value} onChangeText={v => onChange(v)} - editable={editable} + {...props} /> </View> ) |