React Native accessibility (#539)
* React Native accessibility * First round of changes * Latest update * Checkpoint * Wrap up * Lint * Remove unhelpful image hints * Fix navigation * Fix rebase and lint * Mitigate an known issue with the password entry in login * Fix composer dismiss * Remove focus on input elements for web * Remove i and npm * pls work * Remove stray declaration * Regenerate yarn.lock --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
parent
c75c888de2
commit
83959c595d
86 changed files with 2479 additions and 1827 deletions
|
@ -122,12 +122,18 @@ export function Component({}: {}) {
|
|||
editable={!appPassword}
|
||||
returnKeyType="done"
|
||||
onEndEditing={createAppPassword}
|
||||
accessible={true}
|
||||
accessibilityLabel="Name"
|
||||
accessibilityHint="Input name for app password"
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
<TouchableOpacity
|
||||
style={[pal.border, styles.passwordContainer, pal.btn]}
|
||||
onPress={onCopy}>
|
||||
onPress={onCopy}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Copy"
|
||||
accessibilityHint="Copies app password">
|
||||
<Text type="2xl-bold" style={[pal.text]}>
|
||||
{appPassword}
|
||||
</Text>
|
||||
|
|
|
@ -37,7 +37,8 @@ export function Component({prevAltText, onAltTextSet}: Props) {
|
|||
return (
|
||||
<View
|
||||
testID="altTextImageModal"
|
||||
style={[pal.view, styles.container, s.flex1]}>
|
||||
style={[pal.view, styles.container, s.flex1]}
|
||||
nativeID="imageAltText">
|
||||
<Text style={[styles.title, pal.text]}>Add alt text</Text>
|
||||
<TextInput
|
||||
testID="altTextImageInput"
|
||||
|
@ -46,9 +47,17 @@ export function Component({prevAltText, onAltTextSet}: Props) {
|
|||
multiline
|
||||
value={altText}
|
||||
onChangeText={text => setAltText(enforceLen(text, MAX_ALT_TEXT))}
|
||||
accessibilityLabel="Image alt text"
|
||||
accessibilityHint="Sets image alt text for screenreaders"
|
||||
accessibilityLabelledBy="imageAltText"
|
||||
/>
|
||||
<View style={styles.buttonControls}>
|
||||
<TouchableOpacity testID="altTextImageSaveBtn" onPress={onPressSave}>
|
||||
<TouchableOpacity
|
||||
testID="altTextImageSaveBtn"
|
||||
onPress={onPressSave}
|
||||
accessibilityLabel="Save alt text"
|
||||
accessibilityHint={`Saves alt text, which reads: ${altText}`}
|
||||
accessibilityRole="button">
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
@ -61,7 +70,11 @@ export function Component({prevAltText, onAltTextSet}: Props) {
|
|||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
testID="altTextImageCancelBtn"
|
||||
onPress={onPressCancel}>
|
||||
onPress={onPressCancel}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel add image alt text"
|
||||
accessibilityHint="Exits adding alt text to image"
|
||||
onAccessibilityEscape={onPressCancel}>
|
||||
<View style={[styles.button]}>
|
||||
<Text type="button-lg" style={[pal.textLight]}>
|
||||
Cancel
|
||||
|
|
|
@ -30,7 +30,12 @@ export function Component({altText}: Props) {
|
|||
<View style={[styles.text, pal.viewLight]}>
|
||||
<Text style={pal.text}>{altText}</Text>
|
||||
</View>
|
||||
<TouchableOpacity testID="altTextImageSaveBtn" onPress={onPress}>
|
||||
<TouchableOpacity
|
||||
testID="altTextImageSaveBtn"
|
||||
onPress={onPress}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Save"
|
||||
accessibilityHint="Save alt text">
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
|
|
@ -133,7 +133,12 @@ export function Component({onChanged}: {onChanged: () => void}) {
|
|||
<View style={[s.flex1, pal.view]}>
|
||||
<View style={[styles.title, pal.border]}>
|
||||
<View style={styles.titleLeft}>
|
||||
<TouchableOpacity onPress={onPressCancel}>
|
||||
<TouchableOpacity
|
||||
onPress={onPressCancel}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel change handle"
|
||||
accessibilityHint="Exits handle change process"
|
||||
onAccessibilityEscape={onPressCancel}>
|
||||
<Text type="lg" style={pal.textLight}>
|
||||
Cancel
|
||||
</Text>
|
||||
|
@ -148,13 +153,20 @@ export function Component({onChanged}: {onChanged: () => void}) {
|
|||
) : error && !serviceDescription ? (
|
||||
<TouchableOpacity
|
||||
testID="retryConnectButton"
|
||||
onPress={onPressRetryConnect}>
|
||||
onPress={onPressRetryConnect}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Retry change handle"
|
||||
accessibilityHint={`Retries handle change to ${handle}`}>
|
||||
<Text type="xl-bold" style={[pal.link, s.pr5]}>
|
||||
Retry
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
) : canSave ? (
|
||||
<TouchableOpacity onPress={onPressSave}>
|
||||
<TouchableOpacity
|
||||
onPress={onPressSave}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Save handle change"
|
||||
accessibilityHint={`Saves handle change to ${handle}`}>
|
||||
<Text type="2xl-medium" style={pal.link}>
|
||||
Save
|
||||
</Text>
|
||||
|
@ -245,6 +257,9 @@ function ProvidedHandleForm({
|
|||
value={handle}
|
||||
onChangeText={onChangeHandle}
|
||||
editable={!isProcessing}
|
||||
accessible={true}
|
||||
accessibilityLabel="Handle"
|
||||
accessibilityHint="Sets Bluesky username"
|
||||
/>
|
||||
</View>
|
||||
<Text type="md" style={[pal.textLight, s.pl10, s.pt10]}>
|
||||
|
@ -253,7 +268,11 @@ function ProvidedHandleForm({
|
|||
@{createFullHandle(handle, userDomain)}
|
||||
</Text>
|
||||
</Text>
|
||||
<TouchableOpacity onPress={onToggleCustom}>
|
||||
<TouchableOpacity
|
||||
onPress={onToggleCustom}
|
||||
accessibilityRole="button"
|
||||
accessibilityHint="Hosting provider"
|
||||
accessibilityLabel="Opens modal for using custom domain">
|
||||
<Text type="md-medium" style={[pal.link, s.pl10, s.pt5]}>
|
||||
I have my own domain
|
||||
</Text>
|
||||
|
@ -338,7 +357,7 @@ function CustomHandleForm({
|
|||
// =
|
||||
return (
|
||||
<>
|
||||
<Text type="md" style={[pal.text, s.pb5, s.pl5]}>
|
||||
<Text type="md" style={[pal.text, s.pb5, s.pl5]} nativeID="customDomain">
|
||||
Enter the domain you want to use
|
||||
</Text>
|
||||
<View style={[pal.btn, styles.textInputWrapper]}>
|
||||
|
@ -356,6 +375,9 @@ function CustomHandleForm({
|
|||
value={handle}
|
||||
onChangeText={onChangeHandle}
|
||||
editable={!isProcessing}
|
||||
accessibilityLabelledBy="customDomain"
|
||||
accessibilityLabel="Custom domain"
|
||||
accessibilityHint="Input your preferred hosting provider"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.spacer} />
|
||||
|
@ -421,7 +443,10 @@ function CustomHandleForm({
|
|||
)}
|
||||
</Button>
|
||||
<View style={styles.spacer} />
|
||||
<TouchableOpacity onPress={onToggleCustom}>
|
||||
<TouchableOpacity
|
||||
onPress={onToggleCustom}
|
||||
accessibilityLabel="Use default provider"
|
||||
accessibilityHint="Use bsky.social as hosting provider">
|
||||
<Text type="md-medium" style={[pal.link, s.pl10, s.pt5]}>
|
||||
Nevermind, create a handle for me
|
||||
</Text>
|
||||
|
|
|
@ -66,7 +66,12 @@ export function Component({
|
|||
<TouchableOpacity
|
||||
testID="confirmBtn"
|
||||
onPress={onPress}
|
||||
style={[styles.btn]}>
|
||||
style={[styles.btn]}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Confirm"
|
||||
// TODO: This needs to be updated so that modal roles are clear;
|
||||
// Currently there is only one usage for the confirm modal: post deletion
|
||||
accessibilityHint="Confirms a potentially destructive action">
|
||||
<Text style={[s.white, s.bold, s.f18]}>Confirm</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
|
|
@ -34,7 +34,12 @@ export function Component({}: {}) {
|
|||
<View style={styles.bottomSpacer} />
|
||||
</ScrollView>
|
||||
<View style={[styles.btnContainer, pal.borderDark]}>
|
||||
<Pressable testID="sendReportBtn" onPress={onPressDone}>
|
||||
<Pressable
|
||||
testID="sendReportBtn"
|
||||
onPress={onPressDone}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Confirm content moderation settings"
|
||||
accessibilityHint="">
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
@ -48,6 +53,7 @@ export function Component({}: {}) {
|
|||
)
|
||||
}
|
||||
|
||||
// TODO: Refactor this component to pass labels down to each tab
|
||||
const ContentLabelPref = observer(
|
||||
({group}: {group: keyof typeof CONFIGURABLE_LABEL_GROUPS}) => {
|
||||
const store = useStores()
|
||||
|
@ -67,19 +73,20 @@ const ContentLabelPref = observer(
|
|||
<SelectGroup
|
||||
current={store.preferences.contentLabels[group]}
|
||||
onChange={v => store.preferences.setContentLabelPref(group, v)}
|
||||
group={group}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
function SelectGroup({
|
||||
current,
|
||||
onChange,
|
||||
}: {
|
||||
interface SelectGroupProps {
|
||||
current: LabelPreference
|
||||
onChange: (v: LabelPreference) => void
|
||||
}) {
|
||||
group: keyof typeof CONFIGURABLE_LABEL_GROUPS
|
||||
}
|
||||
|
||||
function SelectGroup({current, onChange, group}: SelectGroupProps) {
|
||||
return (
|
||||
<View style={styles.selectableBtns}>
|
||||
<SelectableBtn
|
||||
|
@ -88,12 +95,14 @@ function SelectGroup({
|
|||
label="Hide"
|
||||
left
|
||||
onChange={onChange}
|
||||
group={group}
|
||||
/>
|
||||
<SelectableBtn
|
||||
current={current}
|
||||
value="warn"
|
||||
label="Warn"
|
||||
onChange={onChange}
|
||||
group={group}
|
||||
/>
|
||||
<SelectableBtn
|
||||
current={current}
|
||||
|
@ -101,11 +110,22 @@ function SelectGroup({
|
|||
label="Show"
|
||||
right
|
||||
onChange={onChange}
|
||||
group={group}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
interface SelectableBtnProps {
|
||||
current: string
|
||||
value: LabelPreference
|
||||
label: string
|
||||
left?: boolean
|
||||
right?: boolean
|
||||
onChange: (v: LabelPreference) => void
|
||||
group: keyof typeof CONFIGURABLE_LABEL_GROUPS
|
||||
}
|
||||
|
||||
function SelectableBtn({
|
||||
current,
|
||||
value,
|
||||
|
@ -113,14 +133,8 @@ function SelectableBtn({
|
|||
left,
|
||||
right,
|
||||
onChange,
|
||||
}: {
|
||||
current: string
|
||||
value: LabelPreference
|
||||
label: string
|
||||
left?: boolean
|
||||
right?: boolean
|
||||
onChange: (v: LabelPreference) => void
|
||||
}) {
|
||||
group,
|
||||
}: SelectableBtnProps) {
|
||||
const pal = usePalette('default')
|
||||
const palPrimary = usePalette('inverted')
|
||||
return (
|
||||
|
@ -132,7 +146,10 @@ function SelectableBtn({
|
|||
pal.border,
|
||||
current === value ? palPrimary.view : pal.view,
|
||||
]}
|
||||
onPress={() => onChange(value)}>
|
||||
onPress={() => onChange(value)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={value}
|
||||
accessibilityHint={`Set ${value} for ${group} content moderation policy`}>
|
||||
<Text style={current === value ? palPrimary.text : pal.text}>
|
||||
{label}
|
||||
</Text>
|
||||
|
|
|
@ -86,7 +86,10 @@ export function Component({}: {}) {
|
|||
<>
|
||||
<TouchableOpacity
|
||||
style={styles.mt20}
|
||||
onPress={onPressSendEmail}>
|
||||
onPress={onPressSendEmail}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Send email"
|
||||
accessibilityHint="Sends email with confirmation code for account deletion">
|
||||
<LinearGradient
|
||||
colors={[
|
||||
gradients.blueLight.start,
|
||||
|
@ -102,7 +105,11 @@ export function Component({}: {}) {
|
|||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.btn, s.mt10]}
|
||||
onPress={onCancel}>
|
||||
onPress={onCancel}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel account deletion"
|
||||
accessibilityHint=""
|
||||
onAccessibilityEscape={onCancel}>
|
||||
<Text type="button-lg" style={pal.textLight}>
|
||||
Cancel
|
||||
</Text>
|
||||
|
@ -112,7 +119,11 @@ export function Component({}: {}) {
|
|||
</>
|
||||
) : (
|
||||
<>
|
||||
<Text type="lg" style={styles.description}>
|
||||
{/* TODO: Update this label to be more concise */}
|
||||
<Text
|
||||
type="lg"
|
||||
style={styles.description}
|
||||
nativeID="confirmationCode">
|
||||
Check your inbox for an email with the confirmation code to enter
|
||||
below:
|
||||
</Text>
|
||||
|
@ -123,8 +134,11 @@ export function Component({}: {}) {
|
|||
keyboardAppearance={theme.colorScheme}
|
||||
value={confirmCode}
|
||||
onChangeText={setConfirmCode}
|
||||
accessibilityLabelledBy="confirmationCode"
|
||||
accessibilityLabel="Confirmation code"
|
||||
accessibilityHint="Input confirmation code for account deletion"
|
||||
/>
|
||||
<Text type="lg" style={styles.description}>
|
||||
<Text type="lg" style={styles.description} nativeID="password">
|
||||
Please enter your password as well:
|
||||
</Text>
|
||||
<TextInput
|
||||
|
@ -135,6 +149,9 @@ export function Component({}: {}) {
|
|||
secureTextEntry
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
accessibilityLabelledBy="password"
|
||||
accessibilityLabel="Password"
|
||||
accessibilityHint="Input password for account deletion"
|
||||
/>
|
||||
{error ? (
|
||||
<View style={styles.mt20}>
|
||||
|
@ -149,14 +166,21 @@ export function Component({}: {}) {
|
|||
<>
|
||||
<TouchableOpacity
|
||||
style={[styles.btn, styles.evilBtn, styles.mt20]}
|
||||
onPress={onPressConfirmDelete}>
|
||||
onPress={onPressConfirmDelete}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Confirm delete account"
|
||||
accessibilityHint="">
|
||||
<Text type="button-lg" style={[s.white, s.bold]}>
|
||||
Delete my account
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.btn, s.mt10]}
|
||||
onPress={onCancel}>
|
||||
onPress={onCancel}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel account deletion"
|
||||
accessibilityHint="Exits account deletion process"
|
||||
onAccessibilityEscape={onCancel}>
|
||||
<Text type="button-lg" style={pal.textLight}>
|
||||
Cancel
|
||||
</Text>
|
||||
|
|
|
@ -175,6 +175,9 @@ export function Component({
|
|||
onChangeText={v =>
|
||||
setDisplayName(enforceLen(v, MAX_DISPLAY_NAME))
|
||||
}
|
||||
accessible={true}
|
||||
accessibilityLabel="Display name"
|
||||
accessibilityHint="Edit your display name"
|
||||
/>
|
||||
</View>
|
||||
<View style={s.pb10}>
|
||||
|
@ -188,6 +191,9 @@ export function Component({
|
|||
multiline
|
||||
value={description}
|
||||
onChangeText={v => setDescription(enforceLen(v, MAX_DESCRIPTION))}
|
||||
accessible={true}
|
||||
accessibilityLabel="Description"
|
||||
accessibilityHint="Edit your profile description"
|
||||
/>
|
||||
</View>
|
||||
{isProcessing ? (
|
||||
|
@ -198,7 +204,10 @@ export function Component({
|
|||
<TouchableOpacity
|
||||
testID="editProfileSaveBtn"
|
||||
style={s.mt10}
|
||||
onPress={onPressSave}>
|
||||
onPress={onPressSave}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Save"
|
||||
accessibilityHint="Saves any changes to your profile">
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
@ -211,7 +220,11 @@ export function Component({
|
|||
<TouchableOpacity
|
||||
testID="editProfileCancelBtn"
|
||||
style={s.mt5}
|
||||
onPress={onPressCancel}>
|
||||
onPress={onPressCancel}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel profile editing"
|
||||
accessibilityHint=""
|
||||
onAccessibilityEscape={onPressCancel}>
|
||||
<View style={[styles.btn]}>
|
||||
<Text style={[s.black, s.bold, pal.text]}>Cancel</Text>
|
||||
</View>
|
||||
|
|
|
@ -87,6 +87,7 @@ const InviteCode = observer(
|
|||
({testID, code, used}: {testID: string; code: string; used?: boolean}) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {invitesAvailable} = store.me
|
||||
|
||||
const onPress = React.useCallback(() => {
|
||||
Clipboard.setString(code)
|
||||
|
@ -98,7 +99,14 @@ const InviteCode = observer(
|
|||
<TouchableOpacity
|
||||
testID={testID}
|
||||
style={[styles.inviteCode, pal.border]}
|
||||
onPress={onPress}>
|
||||
onPress={onPress}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={
|
||||
invitesAvailable === 1
|
||||
? 'Invite codes: 1 available'
|
||||
: `Invite codes: ${invitesAvailable} available`
|
||||
}
|
||||
accessibilityHint="Opens list of invite codes">
|
||||
<Text
|
||||
testID={`${testID}-code`}
|
||||
type={used ? 'md' : 'md-bold'}
|
||||
|
|
|
@ -53,6 +53,7 @@ function Modal({modal}: {modal: ModalIface}) {
|
|||
store.shell.closeModal()
|
||||
}
|
||||
const onInnerPress = () => {
|
||||
// TODO: can we use prevent default?
|
||||
// do nothing, we just want to stop it from bubbling
|
||||
}
|
||||
|
||||
|
@ -92,8 +93,10 @@ function Modal({modal}: {modal: ModalIface}) {
|
|||
}
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line
|
||||
<TouchableWithoutFeedback onPress={onPressMask}>
|
||||
<View style={styles.mask}>
|
||||
{/* eslint-disable-next-line */}
|
||||
<TouchableWithoutFeedback onPress={onInnerPress}>
|
||||
<View
|
||||
style={[
|
||||
|
|
|
@ -110,7 +110,10 @@ export function Component({did}: {did: string}) {
|
|||
<TouchableOpacity
|
||||
testID="sendReportBtn"
|
||||
style={s.mt10}
|
||||
onPress={onPress}>
|
||||
onPress={onPress}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Report account"
|
||||
accessibilityHint={`Reports account with reason ${issue}`}>
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
|
|
@ -153,7 +153,10 @@ export function Component({
|
|||
<TouchableOpacity
|
||||
testID="sendReportBtn"
|
||||
style={s.mt10}
|
||||
onPress={onPress}>
|
||||
onPress={onPress}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Report post"
|
||||
accessibilityHint={`Reports post with reason ${issue}`}>
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
|
|
@ -18,6 +18,7 @@ export function Component({
|
|||
onRepost: () => void
|
||||
onQuote: () => void
|
||||
isReposted: boolean
|
||||
// TODO: Add author into component
|
||||
}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
|
@ -31,7 +32,10 @@ export function Component({
|
|||
<TouchableOpacity
|
||||
testID="repostBtn"
|
||||
style={[styles.actionBtn]}
|
||||
onPress={onRepost}>
|
||||
onPress={onRepost}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={isReposted ? 'Undo repost' : 'Repost'}
|
||||
accessibilityHint={isReposted ? 'Remove repost' : 'Repost '}>
|
||||
<RepostIcon strokeWidth={2} size={24} style={s.blue3} />
|
||||
<Text type="title-lg" style={[styles.actionBtnLabel, pal.text]}>
|
||||
{!isReposted ? 'Repost' : 'Undo repost'}
|
||||
|
@ -40,14 +44,23 @@ export function Component({
|
|||
<TouchableOpacity
|
||||
testID="quoteBtn"
|
||||
style={[styles.actionBtn]}
|
||||
onPress={onQuote}>
|
||||
onPress={onQuote}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Quote post"
|
||||
accessibilityHint="">
|
||||
<FontAwesomeIcon icon="quote-left" size={24} style={s.blue3} />
|
||||
<Text type="title-lg" style={[styles.actionBtnLabel, pal.text]}>
|
||||
Quote Post
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<TouchableOpacity testID="cancelBtn" onPress={onPress}>
|
||||
<TouchableOpacity
|
||||
testID="cancelBtn"
|
||||
onPress={onPress}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel quote post"
|
||||
accessibilityHint=""
|
||||
onAccessibilityEscape={onPress}>
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
|
|
@ -41,7 +41,8 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
|
|||
<TouchableOpacity
|
||||
testID="localDevServerButton"
|
||||
style={styles.btn}
|
||||
onPress={() => doSelect(LOCAL_DEV_SERVICE)}>
|
||||
onPress={() => doSelect(LOCAL_DEV_SERVICE)}
|
||||
accessibilityRole="button">
|
||||
<Text style={styles.btnText}>Local dev server</Text>
|
||||
<FontAwesomeIcon
|
||||
icon="arrow-right"
|
||||
|
@ -50,7 +51,8 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
|
|||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.btn}
|
||||
onPress={() => doSelect(STAGING_SERVICE)}>
|
||||
onPress={() => doSelect(STAGING_SERVICE)}
|
||||
accessibilityRole="button">
|
||||
<Text style={styles.btnText}>Staging</Text>
|
||||
<FontAwesomeIcon
|
||||
icon="arrow-right"
|
||||
|
@ -61,7 +63,10 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
|
|||
) : undefined}
|
||||
<TouchableOpacity
|
||||
style={styles.btn}
|
||||
onPress={() => doSelect(PROD_SERVICE)}>
|
||||
onPress={() => doSelect(PROD_SERVICE)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Select Bluesky Social"
|
||||
accessibilityHint="Sets Bluesky Social as your service provider">
|
||||
<Text style={styles.btnText}>Bluesky.Social</Text>
|
||||
<FontAwesomeIcon
|
||||
icon="arrow-right"
|
||||
|
@ -83,11 +88,23 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
|
|||
keyboardAppearance={theme.colorScheme}
|
||||
value={customUrl}
|
||||
onChangeText={setCustomUrl}
|
||||
accessibilityLabel="Custom domain"
|
||||
// TODO: Simplify this wording further to be understandable by everyone
|
||||
accessibilityHint="Use your domain as your Bluesky client service provider"
|
||||
/>
|
||||
<TouchableOpacity
|
||||
testID="customServerSelectBtn"
|
||||
style={[pal.borderDark, pal.text, styles.textInputBtn]}
|
||||
onPress={() => doSelect(customUrl)}>
|
||||
onPress={() => doSelect(customUrl)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`Confirm service. ${
|
||||
customUrl === ''
|
||||
? 'Button disabled. Input custom domain to proceed.'
|
||||
: ''
|
||||
}`}
|
||||
accessibilityHint=""
|
||||
// TODO - accessibility: Need to inform state change on failure
|
||||
disabled={customUrl === ''}>
|
||||
<FontAwesomeIcon
|
||||
icon="check"
|
||||
style={[pal.text as FontAwesomeIconStyle, styles.checkIcon]}
|
||||
|
|
|
@ -77,6 +77,9 @@ export function Component({}: {}) {
|
|||
keyboardAppearance={theme.colorScheme}
|
||||
value={email}
|
||||
onChangeText={setEmail}
|
||||
accessible={true}
|
||||
accessibilityLabel="Email"
|
||||
accessibilityHint="Input your email to get on the Bluesky waitlist"
|
||||
/>
|
||||
{error ? (
|
||||
<View style={s.mt10}>
|
||||
|
@ -99,7 +102,10 @@ export function Component({}: {}) {
|
|||
</View>
|
||||
) : (
|
||||
<>
|
||||
<TouchableOpacity onPress={onPressSignup}>
|
||||
<TouchableOpacity
|
||||
onPress={onPressSignup}
|
||||
accessibilityRole="button"
|
||||
accessibilityHint={`Confirms signing up ${email} to the waitlist`}>
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
@ -110,7 +116,13 @@ export function Component({}: {}) {
|
|||
</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={[styles.btn, s.mt10]} onPress={onCancel}>
|
||||
<TouchableOpacity
|
||||
style={[styles.btn, s.mt10]}
|
||||
onPress={onCancel}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel waitlist signup"
|
||||
accessibilityHint={`Exits signing up for waitlist with ${email}`}
|
||||
onAccessibilityEscape={onCancel}>
|
||||
<Text type="button-lg" style={pal.textLight}>
|
||||
Cancel
|
||||
</Text>
|
||||
|
|
|
@ -4,12 +4,13 @@ import ImageEditor from 'react-avatar-editor'
|
|||
import {Slider} from '@miblanchard/react-native-slider'
|
||||
import LinearGradient from 'react-native-linear-gradient'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {Dimensions, Image} from 'lib/media/types'
|
||||
import {Dimensions} from 'lib/media/types'
|
||||
import {getDataUriSize} from 'lib/media/util'
|
||||
import {s, gradients} from 'lib/styles'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {SquareIcon, RectWideIcon, RectTallIcon} from 'lib/icons'
|
||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||
|
||||
enum AspectRatio {
|
||||
Square = 'square',
|
||||
|
@ -30,7 +31,7 @@ export function Component({
|
|||
onSelect,
|
||||
}: {
|
||||
uri: string
|
||||
onSelect: (img?: Image) => void
|
||||
onSelect: (img?: RNImage) => void
|
||||
}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
|
@ -92,19 +93,31 @@ export function Component({
|
|||
maximumValue={3}
|
||||
containerStyle={styles.slider}
|
||||
/>
|
||||
<TouchableOpacity onPress={doSetAs(AspectRatio.Wide)}>
|
||||
<TouchableOpacity
|
||||
onPress={doSetAs(AspectRatio.Wide)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Wide"
|
||||
accessibilityHint="Sets image aspect ratio to wide">
|
||||
<RectWideIcon
|
||||
size={24}
|
||||
style={as === AspectRatio.Wide ? s.blue3 : undefined}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={doSetAs(AspectRatio.Tall)}>
|
||||
<TouchableOpacity
|
||||
onPress={doSetAs(AspectRatio.Tall)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Tall"
|
||||
accessibilityHint="Sets image aspect ratio to tall">
|
||||
<RectTallIcon
|
||||
size={24}
|
||||
style={as === AspectRatio.Tall ? s.blue3 : undefined}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={doSetAs(AspectRatio.Square)}>
|
||||
<TouchableOpacity
|
||||
onPress={doSetAs(AspectRatio.Square)}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Square"
|
||||
accessibilityHint="Sets image aspect ratio to square">
|
||||
<SquareIcon
|
||||
size={24}
|
||||
style={as === AspectRatio.Square ? s.blue3 : undefined}
|
||||
|
@ -112,13 +125,21 @@ export function Component({
|
|||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.btns}>
|
||||
<TouchableOpacity onPress={onPressCancel}>
|
||||
<TouchableOpacity
|
||||
onPress={onPressCancel}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Cancel image crop"
|
||||
accessibilityHint="Exits image cropping process">
|
||||
<Text type="xl" style={pal.link}>
|
||||
Cancel
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={s.flex1} />
|
||||
<TouchableOpacity onPress={onPressDone}>
|
||||
<TouchableOpacity
|
||||
onPress={onPressDone}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Save image crop"
|
||||
accessibilityHint="Saves image crop settings">
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue