Skip to content

Commit 554270b

Browse files
chore(runway): cherry-pick fix(perps): watchlist and explore header and list padding fix cp-7.64.0 (#25422)
- fix(perps): watchlist and explore header and list padding fix cp-7.64.0 (#25407) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> - Fix header font weight to match Figma design specs (500 Medium instead of 700 Bold) - Implement dynamic header padding based on context (balance visibility, watchlist presence) - Remove redundant horizontal padding from Watchlist component (inherited from parent) - Increase explore market row vertical padding from 6px to 16px - Add horizontal margin to "See All Perps" button Changes Font Weight: - Changed Watchlist and Explore headers from TextVariant.HeadingMD to TextVariant.BodyLGMedium Dynamic Header Padding: - Watchlist header: 16px/4px (no balance) or 24px/4px (with balance) - Explore header: 16px/4px (no balance), 24px/4px (with balance), or 20px/8px (below watchlist) Padding Cleanup: - Removed duplicate paddingHorizontal: 16 from watchlist header/list (inherits from parent) - Updated explore market row paddingVertical from 6px to 16px - Added marginHorizontal: 16 to "See All Perps" button ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fix watchlist and explore header and list padding ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` - Verify Watchlist/Explore headers display with Medium font weight (500) - Verify header padding adjusts correctly when balance is empty vs non-empty - Verify Explore header spacing changes when Watchlist is visible vs hidden - Verify market row spacing matches Figma spec ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Mostly UI/layout refactors, but it changes how the Perps tab renders the watchlist and removes the pressable watchlist header in `PerpsWatchlistMarkets`, which could impact navigation/interaction if relied on elsewhere. > > **Overview** > Aligns Perps home/tab UI spacing with updated design specs by switching section headers to `TextVariant.BodyLGMedium`, increasing header bottom margins, and adjusting row/button padding. > > Refactors `PerpsTabView` to render the watchlist inline (using `PerpsMarketRowItem`) and apply *dynamic* explore header padding based on balance visibility and whether the watchlist is present; also adds horizontal margin to the "See all perps" button. > > Simplifies `PerpsWatchlistMarkets` by removing the pressable header/chevron navigation and updating header spacing, and updates tests/mocks (including `usePerpsLivePrices` and market row selectors) to match the new rendering. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 0350f76. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> [74f8159](74f8159) Co-authored-by: Matt D. <85914066+geositta@users.noreply.github.com>
1 parent 0ee7328 commit 554270b

8 files changed

Lines changed: 98 additions & 140 deletions

File tree

app/components/UI/Perps/Views/PerpsTabView/PerpsTabView.styles.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,45 +93,47 @@ const styleSheet = (params: { theme: Theme }) => {
9393
marginLeft: 12,
9494
flex: 1,
9595
},
96-
// Section style overrides for PerpsTabView - flat list without card styling
97-
watchlistSectionStyle: {
96+
// Watchlist section - inline render (not using shared PerpsWatchlistMarkets component)
97+
watchlistSection: {
9898
marginBottom: 0,
9999
},
100100
watchlistHeaderStyleNoBalance: {
101101
paddingTop: 16,
102-
paddingHorizontal: 16,
103102
paddingBottom: 4,
104103
marginBottom: 0,
105104
},
106105
watchlistHeaderStyleWithBalance: {
107106
paddingTop: 24,
108-
paddingHorizontal: 16,
109107
paddingBottom: 4,
110108
marginBottom: 0,
111109
},
112-
// Flat content container - no card styling
113-
// Note: horizontal padding comes from internal listContent/PerpsMarketList styles
114-
flatContentContainerStyle: {
115-
marginHorizontal: 0,
116-
borderRadius: 0,
117-
paddingTop: 0,
118-
paddingBottom: 0,
119-
backgroundColor: colors.background.default,
120-
},
121110
// Custom explore section styles - isolated from shared components
122111
exploreSection: {
123112
marginBottom: 0,
124113
},
125-
exploreSectionHeader: {
126-
paddingTop: 8,
114+
// Explore header: at top, no balance - 16px/4px
115+
exploreSectionHeaderNoBalance: {
116+
paddingTop: 16,
117+
paddingBottom: 4,
118+
marginBottom: 0,
119+
},
120+
// Explore header: at top, with balance - 24px/4px
121+
exploreSectionHeaderWithBalance: {
122+
paddingTop: 24,
123+
paddingBottom: 4,
124+
marginBottom: 0,
125+
},
126+
// Explore header: below watchlist - 20px/8px
127+
exploreSectionHeaderBelowWatchlist: {
128+
paddingTop: 20,
127129
paddingBottom: 8,
128130
marginBottom: 0,
129131
},
130132
exploreMarketRow: {
131133
flexDirection: 'row',
132134
justifyContent: 'space-between',
133135
alignItems: 'center',
134-
paddingVertical: 6,
136+
paddingVertical: 16,
135137
},
136138
exploreMarketLeft: {
137139
flexDirection: 'row',
@@ -175,6 +177,7 @@ const styleSheet = (params: { theme: Theme }) => {
175177
justifyContent: 'center',
176178
marginTop: 12,
177179
marginBottom: 12,
180+
marginHorizontal: 16,
178181
},
179182
});
180183
};

app/components/UI/Perps/Views/PerpsTabView/PerpsTabView.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ jest.mock('../../hooks/stream', () => ({
111111
},
112112
isInitialLoading: false,
113113
})),
114+
usePerpsLivePrices: jest.fn(() => ({})),
114115
}));
115116

116117
// Mock formatUtils
@@ -165,6 +166,11 @@ jest.mock('../../Perps.testIds', () => ({
165166
POSITIONS_SECTION_TITLE: 'perps-positions-section-title',
166167
POSITION_ITEM: 'perps-positions-item',
167168
},
169+
getPerpsMarketRowItemSelector: {
170+
rowItem: (symbol: string) => `perps-market-row-${symbol}`,
171+
tokenLogo: (symbol: string) => `perps-market-logo-${symbol}`,
172+
badge: (symbol: string) => `perps-market-badge-${symbol}`,
173+
},
168174
}));
169175

170176
// Import after mock to use the mocked values

app/components/UI/Perps/Views/PerpsTabView/PerpsTabView.tsx

Lines changed: 61 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,11 @@ import {
4242
usePerpsTabExploreData,
4343
} from '../../hooks';
4444
import { usePerpsLiveAccount, usePerpsLiveOrders } from '../../hooks/stream';
45-
import PerpsWatchlistMarkets from '../../components/PerpsWatchlistMarkets/PerpsWatchlistMarkets';
4645
import { usePerpsMeasurement } from '../../hooks/usePerpsMeasurement';
4746
import { getPositionDirection } from '../../utils/positionCalculations';
4847
import styleSheet from './PerpsTabView.styles';
49-
import PerpsTokenLogo from '../../components/PerpsTokenLogo';
50-
import PerpsLeverage from '../../components/PerpsLeverage/PerpsLeverage';
51-
import PerpsBadge from '../../components/PerpsBadge';
52-
import {
53-
getPerpsDisplaySymbol,
54-
getMarketBadgeType,
55-
} from '../../utils/marketUtils';
56-
import { HOME_SCREEN_CONFIG } from '../../constants/perpsConfig';
5748
import PerpsRowSkeleton from '../../components/PerpsRowSkeleton';
49+
import PerpsMarketRowItem from '../../components/PerpsMarketRowItem';
5850

5951
import Skeleton from '../../../../../component-library/components/Skeleton/Skeleton';
6052
import ConditionalScrollView from '../../../../../component-library/components-temp/ConditionalScrollView';
@@ -117,6 +109,13 @@ const PerpsTabView = () => {
117109
// Check if watchlist is visible (for conditional rendering)
118110
const isWatchlistVisible = watchlistMarkets.length > 0;
119111

112+
// Explore header: depends on position and balance
113+
const exploreSectionHeaderStyle = isWatchlistVisible
114+
? styles.exploreSectionHeaderBelowWatchlist // 20px/8px
115+
: shouldShowBalance
116+
? styles.exploreSectionHeaderWithBalance // 24px/4px
117+
: styles.exploreSectionHeaderNoBalance; // 16px/4px
118+
120119
// Track wallet home perps tab viewed - declarative (main's event name, privacy-compliant count)
121120
usePerpsEventTracking({
122121
eventName: MetaMetricsEvents.PERPS_SCREEN_VIEWED,
@@ -297,74 +296,55 @@ const PerpsTabView = () => {
297296
});
298297
}, [navigation]);
299298

300-
const renderExploreMarketRow = useCallback(
301-
(market: PerpsMarketData) => {
302-
const badgeType = getMarketBadgeType(market);
303-
const isPositiveChange = !market.change24h.startsWith('-');
304-
299+
const renderWatchlistSection = useCallback(() => {
300+
if (isExploreLoading) {
305301
return (
306-
<TouchableOpacity
307-
key={market.symbol}
308-
style={styles.exploreMarketRow}
309-
onPress={() => handleExploreMarketPress(market)}
310-
>
311-
<View style={styles.exploreMarketLeft}>
312-
<View style={styles.exploreMarketIcon}>
313-
<PerpsTokenLogo
314-
symbol={market.symbol}
315-
size={HOME_SCREEN_CONFIG.DefaultIconSize}
316-
/>
317-
</View>
318-
<View style={styles.exploreMarketInfo}>
319-
<View style={styles.exploreMarketHeader}>
320-
<Text
321-
variant={TextVariant.BodyMDMedium}
322-
color={TextColor.Default}
323-
>
324-
{getPerpsDisplaySymbol(market.symbol)}
325-
</Text>
326-
<PerpsLeverage maxLeverage={market.maxLeverage} />
327-
</View>
328-
<View style={styles.exploreMarketSecondRow}>
329-
<Text
330-
variant={TextVariant.BodySM}
331-
color={TextColor.Alternative}
332-
numberOfLines={1}
333-
>
334-
{market.volume} {strings('perps.sort.volume_short')}
335-
</Text>
336-
{badgeType && <PerpsBadge type={badgeType} />}
337-
</View>
338-
</View>
339-
</View>
340-
<View style={styles.exploreMarketRight}>
341-
<Text
342-
variant={TextVariant.BodyMDMedium}
343-
color={TextColor.Default}
344-
style={styles.exploreMarketPrice}
345-
>
346-
{market.price}
347-
</Text>
348-
<Text
349-
variant={TextVariant.BodySM}
350-
color={isPositiveChange ? TextColor.Success : TextColor.Error}
351-
style={styles.exploreMarketChange}
352-
>
353-
{market.change24hPercent}
302+
<View style={styles.watchlistSection}>
303+
<View style={watchlistHeaderStyle}>
304+
<Text variant={TextVariant.BodyLGMedium} color={TextColor.Default}>
305+
{strings('perps.home.watchlist')}
354306
</Text>
355307
</View>
356-
</TouchableOpacity>
308+
<PerpsRowSkeleton count={3} />
309+
</View>
357310
);
358-
},
359-
[styles, handleExploreMarketPress],
360-
);
311+
}
312+
313+
if (watchlistMarkets.length === 0) {
314+
return null;
315+
}
316+
317+
return (
318+
<View style={styles.watchlistSection}>
319+
<View style={watchlistHeaderStyle}>
320+
<Text variant={TextVariant.BodyLGMedium} color={TextColor.Default}>
321+
{strings('perps.home.watchlist')}
322+
</Text>
323+
</View>
324+
{watchlistMarkets.map((market) => (
325+
<PerpsMarketRowItem
326+
key={market.symbol}
327+
market={market}
328+
showBadge={false}
329+
onPress={() => handleExploreMarketPress(market)}
330+
/>
331+
))}
332+
</View>
333+
);
334+
}, [
335+
isExploreLoading,
336+
watchlistMarkets,
337+
styles,
338+
watchlistHeaderStyle,
339+
handleExploreMarketPress,
340+
]);
361341

362342
const renderExploreSection = useCallback(() => {
363343
if (isExploreLoading) {
364344
return (
365345
<View style={styles.exploreSection}>
366-
<View style={styles.exploreSectionHeader}>
367-
<Text variant={TextVariant.BodyMDMedium} color={TextColor.Default}>
346+
<View style={exploreSectionHeaderStyle}>
347+
<Text variant={TextVariant.BodyLGMedium} color={TextColor.Default}>
368348
{strings('perps.home.explore_markets')}
369349
</Text>
370350
</View>
@@ -379,12 +359,18 @@ const PerpsTabView = () => {
379359

380360
return (
381361
<View style={styles.exploreSection}>
382-
<View style={styles.exploreSectionHeader}>
383-
<Text variant={TextVariant.BodyMDMedium} color={TextColor.Default}>
362+
<View style={exploreSectionHeaderStyle}>
363+
<Text variant={TextVariant.BodyLGMedium} color={TextColor.Default}>
384364
{strings('perps.home.explore_markets')}
385365
</Text>
386366
</View>
387-
<View>{exploreMarkets.map(renderExploreMarketRow)}</View>
367+
{exploreMarkets.map((market) => (
368+
<PerpsMarketRowItem
369+
key={market.symbol}
370+
market={market}
371+
onPress={() => handleExploreMarketPress(market)}
372+
/>
373+
))}
388374
<TouchableOpacity
389375
style={styles.seeAllButton}
390376
onPress={handleSeeAllPerps}
@@ -399,7 +385,8 @@ const PerpsTabView = () => {
399385
isExploreLoading,
400386
exploreMarkets,
401387
styles,
402-
renderExploreMarketRow,
388+
exploreSectionHeaderStyle,
389+
handleExploreMarketPress,
403390
handleSeeAllPerps,
404391
]);
405392

@@ -425,18 +412,8 @@ const PerpsTabView = () => {
425412
>
426413
{!isInitialLoading && hasNoPositionsOrOrders ? (
427414
<View style={styles.emptyStateContainer}>
428-
{/* Watchlist section - only render if user has watchlist markets */}
429-
{isWatchlistVisible && (
430-
<PerpsWatchlistMarkets
431-
markets={watchlistMarkets}
432-
isLoading={isExploreLoading}
433-
positions={[]}
434-
orders={[]}
435-
sectionStyle={styles.watchlistSectionStyle}
436-
headerStyle={watchlistHeaderStyle}
437-
contentContainerStyle={styles.flatContentContainerStyle}
438-
/>
439-
)}
415+
{/* Watchlist section - inline render with PerpsTabView-specific styling */}
416+
{renderWatchlistSection()}
440417

441418
{/* Explore markets section - custom render for PerpsTabView styling */}
442419
{renderExploreSection()}

app/components/UI/Perps/components/PerpsHomeSection/PerpsHomeSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const styles = StyleSheet.create({
6969
},
7070
headerContainer: {
7171
paddingHorizontal: 16,
72-
marginBottom: 8,
72+
marginBottom: 12,
7373
marginTop: 12,
7474
},
7575
titleRow: {

app/components/UI/Perps/components/PerpsMarketTypeSection/PerpsMarketTypeSection.styles.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const styleSheet = (params: { theme: Theme }) => {
1111
flexDirection: 'row',
1212
alignItems: 'center',
1313
paddingHorizontal: 16,
14-
marginBottom: 8,
14+
marginBottom: 12,
1515
},
1616
titleRow: {
1717
flexDirection: 'row',

app/components/UI/Perps/components/PerpsMarketTypeSection/PerpsMarketTypeSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ const PerpsMarketTypeSection: React.FC<PerpsMarketTypeSectionProps> = ({
108108
onPress={handleViewAll}
109109
>
110110
<View style={styles.titleRow}>
111-
<Text variant={TextVariant.HeadingMD} color={TextColor.Default}>
111+
<Text variant={TextVariant.BodyLGMedium} color={TextColor.Default}>
112112
{title}
113113
</Text>
114114
<Icon

app/components/UI/Perps/components/PerpsWatchlistMarkets/PerpsWatchlistMarkets.styles.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const styleSheet = (params: { theme: Theme }) => {
1111
flexDirection: 'row',
1212
alignItems: 'center',
1313
paddingHorizontal: 16,
14-
marginBottom: 8,
14+
marginBottom: 12,
1515
},
1616
titleRow: {
1717
flexDirection: 'row',

app/components/UI/Perps/components/PerpsWatchlistMarkets/PerpsWatchlistMarkets.tsx

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
11
import React, { useCallback } from 'react';
2-
import {
3-
FlatList,
4-
View,
5-
TouchableOpacity,
6-
type StyleProp,
7-
type ViewStyle,
8-
} from 'react-native';
2+
import { FlatList, View, type StyleProp, type ViewStyle } from 'react-native';
93
import { useNavigation, type NavigationProp } from '@react-navigation/native';
104
import Text, {
115
TextVariant,
126
TextColor,
137
} from '../../../../../component-library/components/Texts/Text';
14-
import Icon, {
15-
IconName,
16-
IconSize,
17-
IconColor,
18-
} from '../../../../../component-library/components/Icons/Icon';
198
import { strings } from '../../../../../../locales/i18n';
209
import Routes from '../../../../../constants/navigation/Routes';
2110
import type {
@@ -93,33 +82,16 @@ const PerpsWatchlistMarkets: React.FC<PerpsWatchlistMarketsProps> = ({
9382
[handleMarketPress],
9483
);
9584

96-
const handleViewAll = useCallback(() => {
97-
navigation.navigate(Routes.PERPS.ROOT, {
98-
screen: Routes.PERPS.MARKET_LIST,
99-
params: {},
100-
});
101-
}, [navigation]);
102-
103-
// Header component - full row is pressable with chevron icon next to title
85+
// Header component
10486
const SectionHeader = useCallback(
10587
() => (
106-
<TouchableOpacity
107-
style={[styles.header, headerStyle]}
108-
onPress={handleViewAll}
109-
>
110-
<View style={styles.titleRow}>
111-
<Text variant={TextVariant.HeadingMD} color={TextColor.Default}>
112-
{strings('perps.home.watchlist')}
113-
</Text>
114-
<Icon
115-
name={IconName.ArrowRight}
116-
size={IconSize.Sm}
117-
color={IconColor.Alternative}
118-
/>
119-
</View>
120-
</TouchableOpacity>
88+
<View style={[styles.header, headerStyle]}>
89+
<Text variant={TextVariant.BodyLGMedium} color={TextColor.Default}>
90+
{strings('perps.home.watchlist')}
91+
</Text>
92+
</View>
12193
),
122-
[styles.header, styles.titleRow, handleViewAll, headerStyle],
94+
[styles.header, headerStyle],
12395
);
12496

12597
// Show skeleton during initial load

0 commit comments

Comments
 (0)