about summary refs log tree commit diff
path: root/src/view/com/auth
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/auth')
-rw-r--r--src/view/com/auth/SplashScreen.tsx10
-rw-r--r--src/view/com/auth/SplashScreen.web.tsx13
-rw-r--r--src/view/com/auth/create/CreateAccount.tsx20
-rw-r--r--src/view/com/auth/create/Step1.tsx14
-rw-r--r--src/view/com/auth/create/Step2.tsx33
-rw-r--r--src/view/com/auth/create/Step3.tsx3
-rw-r--r--src/view/com/auth/login/Login.tsx100
-rw-r--r--src/view/com/auth/util/TextInput.tsx25
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>
   )