Skip to content

Commit aba8226

Browse files
perf(accessibility): fix iOS accessibility in Bridge token selector components
- BridgeTokenSelector, TokenButton, TokenSelectorItem: Pressable → TouchableOpacity Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 60a0da0 commit aba8226

3 files changed

Lines changed: 82 additions & 58 deletions

File tree

app/components/UI/Bridge/components/BridgeTokenSelector/BridgeTokenSelector.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,15 @@ export const BridgeTokenSelector: React.FC = () => {
566566
ListFooterComponent={renderFooter}
567567
ListEmptyComponent={renderEmptyState}
568568
onLayout={handleFlatListLayout}
569+
initialNumToRender={8}
570+
maxToRenderPerBatch={5}
571+
windowSize={5}
572+
removeClippedSubviews
573+
getItemLayout={(_data, index) => ({
574+
length: ESTIMATED_ITEM_HEIGHT,
575+
offset: ESTIMATED_ITEM_HEIGHT * index,
576+
index,
577+
})}
569578
/>
570579
</SafeAreaView>
571580
);

app/components/UI/Bridge/components/TokenButton.tsx

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import Text, {
99
} from '../../../../component-library/components/Texts/Text';
1010
import { useStyles } from '../../../../component-library/hooks';
1111
import { Theme } from '../../../../util/theme/models';
12-
import { Box } from '../../Box/Box';
13-
import { FlexDirection, AlignItems, JustifyContent } from '../../Box/box.types';
1412
import BadgeWrapper, {
1513
BadgePosition,
1614
} from '../../../../component-library/components/Badges/BadgeWrapper';
@@ -42,6 +40,10 @@ const createStyles = (params: StylesParams) => {
4240
borderRadius: 16,
4341
},
4442
pillContainer: {
43+
flexDirection: 'row' as const,
44+
alignItems: 'flex-end' as const,
45+
justifyContent: 'flex-end' as const,
46+
gap: 8,
4547
backgroundColor: theme.colors.background.muted,
4648
borderRadius: 100,
4749
paddingLeft: 8,
@@ -67,31 +69,27 @@ export const TokenButton: React.FC<TokenProps> = ({
6769
}) => {
6870
const { styles } = useStyles(createStyles, {});
6971
return (
70-
<TouchableOpacity onPress={onPress} testID={testID}>
71-
<Box
72-
style={styles.pillContainer}
73-
flexDirection={FlexDirection.Row}
74-
alignItems={AlignItems.flexEnd}
75-
justifyContent={JustifyContent.flexEnd}
76-
gap={8}
72+
<TouchableOpacity
73+
onPress={onPress}
74+
testID={testID}
75+
style={styles.pillContainer}
76+
>
77+
<BadgeWrapper
78+
badgePosition={BadgePosition.BottomRight}
79+
badgeElement={
80+
<Badge
81+
variant={BadgeVariant.Network}
82+
imageSource={networkImageSource}
83+
name={networkName}
84+
/>
85+
}
7786
>
78-
<BadgeWrapper
79-
badgePosition={BadgePosition.BottomRight}
80-
badgeElement={
81-
<Badge
82-
variant={BadgeVariant.Network}
83-
imageSource={networkImageSource}
84-
name={networkName}
85-
/>
86-
}
87-
>
88-
<TokenIcon symbol={symbol} icon={iconUrl} style={styles.icon} />
89-
</BadgeWrapper>
87+
<TokenIcon symbol={symbol} icon={iconUrl} style={styles.icon} />
88+
</BadgeWrapper>
9089

91-
<Text style={styles.tokenSymbol} variant={TextVariant.HeadingLG}>
92-
{symbol}
93-
</Text>
94-
</Box>
90+
<Text style={styles.tokenSymbol} variant={TextVariant.HeadingLG}>
91+
{symbol}
92+
</Text>
9593
</TouchableOpacity>
9694
);
9795
};

app/components/UI/Bridge/components/TokenSelectorItem.tsx

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,13 @@ const createStyles = ({
7474
flex: 1,
7575
flexShrink: 1,
7676
minWidth: 0,
77-
marginLeft: 12,
77+
marginLeft: 8,
7878
},
7979
container: {
8080
backgroundColor: vars.isSelected
8181
? theme.colors.primary.muted
8282
: theme.colors.background.default,
8383
paddingVertical: 4,
84-
minHeight: 72,
8584
paddingLeft: 16,
8685
paddingRight: 10,
8786
},
@@ -97,7 +96,7 @@ const createStyles = ({
9796
itemWrapper: {
9897
flex: 1,
9998
flexDirection: 'row',
100-
paddingVertical: 12,
99+
paddingVertical: 10,
101100
alignItems: 'flex-start',
102101
},
103102
tokenMainInfo: {
@@ -263,7 +262,28 @@ const TokenBalanceView = ({
263262
);
264263
};
265264

266-
export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
265+
const formatTokenBalance = (balance: string): string => {
266+
const numericBalance = Number(balance);
267+
if (numericBalance === 0) {
268+
return '0';
269+
}
270+
if (numericBalance < 0.00001) {
271+
return '< 0.00001';
272+
}
273+
return parseAmount(balance, 5) || balance;
274+
};
275+
276+
const TOP_ROW_BALANCE_TEXT_STYLE = {
277+
textVariant: TextVariant.BodyMDMedium,
278+
textColor: TextColor.Default,
279+
} as const;
280+
281+
const BOTTOM_ROW_BALANCE_TEXT_STYLE = {
282+
textVariant: TextVariant.BodyMD,
283+
textColor: TextColor.Alternative,
284+
} as const;
285+
286+
const TokenSelectorItemInner: React.FC<TokenSelectorItemProps> = ({
267287
token,
268288
onPress,
269289
networkName,
@@ -286,17 +306,6 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
286306

287307
const fiatValue = token.balanceFiat;
288308

289-
const formatTokenBalance = (balance: string): string => {
290-
const numericBalance = Number(balance);
291-
if (numericBalance === 0) {
292-
return '0';
293-
}
294-
if (numericBalance < 0.00001) {
295-
return '< 0.00001';
296-
}
297-
return parseAmount(balance, 5) || balance;
298-
};
299-
300309
const selectedVariant =
301310
variant ??
302311
TOKEN_SELECTOR_BALANCE_LAYOUT_VARIANTS[
@@ -313,19 +322,10 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
313322

314323
const isNative = token.address === ethers.constants.AddressZero;
315324

316-
// to check if the token is a stock by checking if the name includes 'ondo' or 'stock'
317325
const { isStockToken } = useRWAToken();
318326

319327
const fiatBalance = shouldShowBalance ? fiatValue : undefined;
320328
const tokenBalance = shouldShowBalance ? cryptoBalance : undefined;
321-
const topRowBalanceTextStyle = {
322-
textVariant: TextVariant.BodyMDMedium,
323-
textColor: TextColor.Default,
324-
};
325-
const bottomRowBalanceTextStyle = {
326-
textVariant: TextVariant.BodySM,
327-
textColor: TextColor.Alternative,
328-
};
329329

330330
const label = token.accountType
331331
? ACCOUNT_TYPE_LABELS[token.accountType]
@@ -335,6 +335,7 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
335335

336336
return (
337337
<Box
338+
accessible={false}
338339
flexDirection={FlexDirection.Row}
339340
alignItems={AlignItems.center}
340341
style={styles.container}
@@ -351,11 +352,11 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
351352
)}
352353
>
353354
<Box
355+
accessible={false}
354356
flexDirection={FlexDirection.Row}
355357
alignItems={AlignItems.center}
356358
gap={4}
357359
>
358-
{/* Token Icon */}
359360
<BadgeWrapper
360361
style={styles.badgeWrapper}
361362
badgePosition={BadgePosition.BottomRight}
@@ -370,7 +371,7 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
370371
<AvatarToken
371372
name={token.symbol}
372373
imageSource={getTokenImageSource(token.symbol, token.image)}
373-
size={AvatarSize.Lg}
374+
size={AvatarSize.Md}
374375
testID={
375376
isNative
376377
? `network-logo-${token.symbol}`
@@ -379,19 +380,20 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
379380
/>
380381
</BadgeWrapper>
381382

382-
{/* Token symbol/name on the left, balances on the right (extension layout pattern) */}
383383
<Box
384+
accessible={false}
384385
style={styles.tokenInfo}
385386
flexDirection={FlexDirection.Column}
386387
gap={4}
387388
>
388389
<Box
390+
accessible={false}
389391
flexDirection={FlexDirection.Row}
390392
alignItems={AlignItems.center}
391393
justifyContent={JustifyContent.spaceBetween}
392394
>
393-
<Box style={styles.tokenMainInfo} gap={4}>
394-
<Box style={styles.tokenSymbolRow}>
395+
<Box accessible={false} style={styles.tokenMainInfo} gap={4}>
396+
<Box accessible={false} style={styles.tokenSymbolRow}>
395397
<Text
396398
variant={TextVariant.BodyMDMedium}
397399
numberOfLines={1}
@@ -445,19 +447,20 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
445447
balance={tokenBalance}
446448
isSelected={isSelected}
447449
textStyle={styles.rightValue}
448-
{...topRowBalanceTextStyle}
450+
{...TOP_ROW_BALANCE_TEXT_STYLE}
449451
/>
450452
) : (
451453
<FiatBalanceView
452454
balance={fiatBalance}
453455
isSelected={isSelected}
454456
textStyle={styles.rightValue}
455-
{...topRowBalanceTextStyle}
457+
{...TOP_ROW_BALANCE_TEXT_STYLE}
456458
/>
457459
)}
458460
</Box>
459461

460462
<Box
463+
accessible={false}
461464
flexDirection={FlexDirection.Row}
462465
alignItems={AlignItems.center}
463466
justifyContent={JustifyContent.spaceBetween}
@@ -477,14 +480,14 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
477480
balance={fiatBalance}
478481
isSelected={isSelected}
479482
textStyle={styles.rightValue}
480-
{...bottomRowBalanceTextStyle}
483+
{...BOTTOM_ROW_BALANCE_TEXT_STYLE}
481484
/>
482485
) : (
483486
<TokenBalanceView
484487
balance={tokenBalance}
485488
isSelected={isSelected}
486489
textStyle={styles.rightValue}
487-
{...bottomRowBalanceTextStyle}
490+
{...BOTTOM_ROW_BALANCE_TEXT_STYLE}
488491
/>
489492
)}
490493
</Box>
@@ -497,3 +500,17 @@ export const TokenSelectorItem: React.FC<TokenSelectorItemProps> = ({
497500
</Box>
498501
);
499502
};
503+
504+
export const TokenSelectorItem = React.memo(
505+
TokenSelectorItemInner,
506+
(prev, next) =>
507+
prev.onPress === next.onPress &&
508+
prev.token.address === next.token.address &&
509+
prev.token.chainId === next.token.chainId &&
510+
prev.token.balance === next.token.balance &&
511+
prev.token.balanceFiat === next.token.balanceFiat &&
512+
prev.isSelected === next.isSelected &&
513+
prev.isNoFeeAsset === next.isNoFeeAsset &&
514+
prev.shouldShowBalance === next.shouldShowBalance &&
515+
prev.networkName === next.networkName,
516+
);

0 commit comments

Comments
 (0)