Skip to content

fix(predict): keep time-slot scroll anchored left when live slot expires cp-7.81.0#31231

Merged
ghgoodreau merged 3 commits into
mainfrom
fix/predict-crypto-time-slot-scroll-anchor
Jun 9, 2026
Merged

fix(predict): keep time-slot scroll anchored left when live slot expires cp-7.81.0#31231
ghgoodreau merged 3 commits into
mainfrom
fix/predict-crypto-time-slot-scroll-anchor

Conversation

@ghgoodreau

@ghgoodreau ghgoodreau commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Description

This PR bundles four UI/behavior fixes on the Predict crypto up/down details screen (plus one shared positions tweak). All changes are confined to app/components/UI/Predict/.

1. Time-slot picker loses its left anchor when the live slot expires (primary fix)
When the live time slot expired and rolled to the next window, the horizontal TimeSlotPicker no longer kept the live/selected pill anchored at the left. Root cause: the auto-scroll read pill x-coordinates from a cached pillPositions map that (1) retained stale entries for markets that had been filtered out, and (2) was read by a fixed 50ms settle timer that raced ahead of React Native's async re-layout — so scrollTo used the pre-shift offset and over-scrolled.

  • Prune pillPositions to only currently-rendered markets whenever markets changes.
  • Re-run the settle-delay anchor on the ordered marketsKey so a left shift re-anchors even when the resolved selection is unchanged.
  • Re-anchor immediately when the selected pill reports a new layout x, beating the timer/layout race.
  • Adds a regression test that reproduces the expiry race (verified failing pre-fix, passing post-fix).

2. Even spacing around the time-slot picker
The picker is a flush h-11 container with no vertical padding of its own, so the gap above (title pb-3 = 12px) and below (price summary pt-5 = 20px) were uneven. Changed the price-summary top padding pt-5 → pt-3 so the picker has equal 12px above and below.

3. Centered separator dot in positions rows
The Up/Down · entry separator dot was baseline-glued to the entry label via a ' · ' string, so it sat slightly off-center. Split it into its own Text node so it aligns optically in the center-aligned row.

4. Remove the $100 → $X payout preview from the up/down CTA + grow the chart
Removed the payout estimate under the buy buttons on the crypto up/down details page by no longer passing showPayoutEstimate to the shared PredictMarketDetailsActions. The prop, formatter, and gated rendering remain intact on that component for any other surface that wants the preview (none currently enable it), so the change is regression-safe. The freed vertical space is reclaimed by growing the with-positions chart height (ratio 0.4 → 0.44, max 380 → 430) so the chart fills the gap above the sticky actions while keeping the first position row visible and the rest scrollable.

Changelog

CHANGELOG entry: Fixed the Predict crypto up/down time-slot selector so the live slot stays anchored to the left when it rolls to the next window, evened out the spacing around the selector, and removed the payout estimate from the buy buttons to give the price chart more room.

Related issues

Refs: No external ticket — incremental UX polish on the Predict crypto up/down details screen reported during QA review (live-slot scroll anchoring regression, uneven selector spacing, off-center separator dot, payout-preview removal + chart sizing).

Manual testing steps

Feature: Predict crypto up/down details screen

  Scenario: Live time slot stays anchored left when it expires
    Given I am on a crypto up/down market details screen
    And the live time slot is the left-most pill in the selector
    When the live slot expires and the next slot becomes live
    Then the new live slot is anchored to the left edge of the selector
    And the selector is not over-scrolled or visually shifted

  Scenario: Time-slot selector is evenly spaced
    Given I am on a crypto up/down market details screen
    Then the vertical space above and below the time-slot selector is equal

  Scenario: Separator dot is centered in a position row
    Given I am on a crypto up/down market details screen
    And I hold at least one position in the series
    Then the dot between the outcome label and the entry price is vertically centered

  Scenario: No payout preview under the buy buttons and chart fills the space
    Given I am on a crypto up/down market details screen
    Then no "$100 -> $..." payout estimate is shown under the Up and Down buttons
    And the price chart uses the freed space above the sticky action buttons

  Scenario: First position visible and the rest scroll
    Given I am on a crypto up/down market details screen
    And I hold more positions than fit on screen
    Then the first position row is visible above the sticky action buttons
    And the remaining position rows are reachable by scrolling

Screenshots/Recordings

Before

N/A — author to attach device capture before marking Ready for review (changes are visual layout tweaks on the crypto up/down details screen that need a simulator/device to record).

After

N/A — author to attach device capture before marking Ready for review.

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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.

Note

Low Risk
Predict UI-only changes in TimeSlotPicker and crypto up/down details; scroll logic is covered by new tests with no auth or data-path impact.

Overview
Fixes Predict crypto up/down layout and TimeSlotPicker scroll behavior when a live slot rolls off.

Time slot picker: When the live pill disappears and the list shifts left, horizontal scroll no longer drifts off the left edge. Stale pillPositions entries are pruned, anchoring re-runs on marketsKey changes, and the selected pill’s onLayout re-scrolls immediately so a 50ms timer doesn’t win a race against re-layout. Regression tests cover initial anchor and post-expiry re-anchor.

Details screen polish: Price-summary top padding is tightened (pt-5pt-3) so spacing above/below the picker matches. With positions, the chart grows (ratio 0.44, max 430px) after dropping the buy-button payout estimate (showPayoutEstimate no longer passed). Position rows: the · separator is its own Text node for better vertical alignment with the outcome/entry labels.

Reviewed by Cursor Bugbot for commit 8308aa7. Bugbot is set up for automated code reviews on this repo. Configure here.

The crypto up/down time-slot picker lost its left anchor when the live
slot expired and rolled to the next window. The auto-scroll read pill
x-coordinates from a cached map that (1) retained stale entries for
removed markets and (2) was read by a fixed 50ms timer that raced ahead
of React Native's async re-layout, so scrollTo used the pre-shift offset.

- Prune pillPositions to currently-rendered markets on markets change.
- Re-run the settle-delay anchor on the ordered markets key so a left
  shift re-anchors even when the resolved selection is unchanged.
- Re-anchor immediately when the selected pill reports a new layout x,
  beating the timer/layout race.

Adds a scroll-anchoring regression test reproducing the expiry race.
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@mm-token-exchange-service mm-token-exchange-service Bot added team-predict Predict team INVALID-PR-TEMPLATE PR's body doesn't match template labels Jun 8, 2026
@github-actions github-actions Bot added the size-M label Jun 8, 2026
…tions

- PredictCryptoUpDownDetails: price summary pt-5 -> pt-3 so the gap below
  the time-slot picker matches the title's pb-3 above it (equal 12px above
  and below the flush h-11 picker).
- PredictCryptoUpDownPosition: render the 'Up/Down . entry' separator dot as
  its own centered Text node instead of baseline-gluing it to the entry
  label, so it aligns optically in the center-aligned row.
- Drop the $100 -> payout estimate from the crypto up/down details CTA by
  no longer passing showPayoutEstimate. The prop, formatter, and gated
  rendering stay intact on PredictMarketDetailsActions for any other page
  that wants the preview (none currently do), so this is regression-safe.
- Reclaim the vertical space the preview freed: raise the with-positions
  chart height (ratio 0.4 -> 0.44, max 380 -> 430) so the chart fills the
  gap above the sticky actions while keeping the first position row visible
  and the rest scrollable.
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePredictions, SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: @PerformancePredict
  • Risk Level: medium
  • AI Confidence: 88%
click to see 🤖 AI reasoning details

E2E Test Selection:
All 4 changed files are within app/components/UI/Predict/ - the Predictions (Polymarket) feature area.

  1. PredictCryptoUpDownDetails.tsx: UI layout changes - chart height max increased (380→430px), height ratio adjusted (0.4→0.44), top padding reduced (pt-5→pt-3), and showPayoutEstimate prop removed from the positions component. These affect the visual layout of the market details screen.

  2. PredictCryptoUpDownPosition.tsx: Minor text rendering fix splitting the separator dot into its own Text component for proper spacing/rendering.

  3. TimeSlotPicker.tsx: Meaningful logic fix for scroll anchoring race condition. When a time slot expires and is filtered out, the remaining pills shift left. The fix adds: (a) marketsKey memoization to detect market list changes, (b) stale position cache cleanup for expired markets, (c) layout-driven re-anchoring when a pill's position changes. This prevents incorrect scroll positions after slot expiry.

  4. TimeSlotPicker.test.tsx: New unit tests validating the scroll anchoring behavior.

Tag selection rationale:

  • SmokePredictions: Directly covers Polymarket prediction market integration - the PredictCryptoUpDownDetails and TimeSlotPicker are core components of the predictions market details view.
  • SmokeWalletPlatform: Required per SmokePredictions description - Predictions is a section inside the Trending tab, so changes to Predictions views affect Trending.
  • SmokeConfirmations: Required per SmokePredictions description - opening/closing positions are on-chain transactions that go through confirmations.

Performance Test Selection:
The TimeSlotPicker scroll anchoring changes involve layout callbacks, memoization, and scroll position management that could affect rendering performance. The chart height adjustments in PredictCryptoUpDownDetails also affect layout calculations. @PerformancePredict covers prediction market list loading and market details, which directly exercises these modified components.

View GitHub Actions results

@ghgoodreau ghgoodreau marked this pull request as ready for review June 8, 2026 20:41
@ghgoodreau ghgoodreau requested a review from a team as a code owner June 8, 2026 20:41
@github-actions github-actions Bot added the risk:low AI analysis: low risk label Jun 8, 2026
@mm-token-exchange-service mm-token-exchange-service Bot removed the INVALID-PR-TEMPLATE PR's body doesn't match template label Jun 8, 2026
@ghgoodreau ghgoodreau changed the title fix(predict): keep time-slot scroll anchored left when live slot expires fix(predict): keep time-slot scroll anchored left when live slot expires cp-7.81.0 Jun 8, 2026
@ghgoodreau ghgoodreau enabled auto-merge June 8, 2026 21:49
@ghgoodreau ghgoodreau added this pull request to the merge queue Jun 9, 2026
Merged via the queue into main with commit a41a3ca Jun 9, 2026
134 of 137 checks passed
@ghgoodreau ghgoodreau deleted the fix/predict-crypto-time-slot-scroll-anchor branch June 9, 2026 17:53
runway-github Bot added a commit that referenced this pull request Jun 9, 2026
… expires cp-7.81.0 (#31231)

## **Description**

This PR bundles four UI/behavior fixes on the Predict **crypto up/down**
details screen (plus one shared positions tweak). All changes are
confined to `app/components/UI/Predict/`.

**1. Time-slot picker loses its left anchor when the live slot expires
(primary fix)**
When the live time slot expired and rolled to the next window, the
horizontal `TimeSlotPicker` no longer kept the live/selected pill
anchored at the left. Root cause: the auto-scroll read pill
x-coordinates from a cached `pillPositions` map that (1) retained stale
entries for markets that had been filtered out, and (2) was read by a
fixed 50ms settle timer that raced ahead of React Native's async
re-layout — so `scrollTo` used the pre-shift offset and over-scrolled.
- Prune `pillPositions` to only currently-rendered markets whenever
`markets` changes.
- Re-run the settle-delay anchor on the ordered `marketsKey` so a left
shift re-anchors even when the resolved selection is unchanged.
- Re-anchor immediately when the selected pill reports a new layout `x`,
beating the timer/layout race.
- Adds a regression test that reproduces the expiry race (verified
failing pre-fix, passing post-fix).

**2. Even spacing around the time-slot picker**
The picker is a flush `h-11` container with no vertical padding of its
own, so the gap above (title `pb-3` = 12px) and below (price summary
`pt-5` = 20px) were uneven. Changed the price-summary top padding `pt-5
→ pt-3` so the picker has equal 12px above and below.

**3. Centered separator dot in positions rows**
The `Up/Down · entry` separator dot was baseline-glued to the entry
label via a `' · '` string, so it sat slightly off-center. Split it into
its own `Text` node so it aligns optically in the center-aligned row.

**4. Remove the `$100 → $X` payout preview from the up/down CTA + grow
the chart**
Removed the payout estimate under the buy buttons on the crypto up/down
details page by no longer passing `showPayoutEstimate` to the shared
`PredictMarketDetailsActions`. The prop, formatter, and gated rendering
remain intact on that component for any other surface that wants the
preview (none currently enable it), so the change is regression-safe.
The freed vertical space is reclaimed by growing the with-positions
chart height (ratio `0.4 → 0.44`, max `380 → 430`) so the chart fills
the gap above the sticky actions while keeping the first position row
visible and the rest scrollable.

## **Changelog**

CHANGELOG entry: Fixed the Predict crypto up/down time-slot selector so
the live slot stays anchored to the left when it rolls to the next
window, evened out the spacing around the selector, and removed the
payout estimate from the buy buttons to give the price chart more room.

## **Related issues**

Refs: No external ticket — incremental UX polish on the Predict crypto
up/down details screen reported during QA review (live-slot scroll
anchoring regression, uneven selector spacing, off-center separator dot,
payout-preview removal + chart sizing).

## **Manual testing steps**

```gherkin
Feature: Predict crypto up/down details screen

  Scenario: Live time slot stays anchored left when it expires
    Given I am on a crypto up/down market details screen
    And the live time slot is the left-most pill in the selector
    When the live slot expires and the next slot becomes live
    Then the new live slot is anchored to the left edge of the selector
    And the selector is not over-scrolled or visually shifted

  Scenario: Time-slot selector is evenly spaced
    Given I am on a crypto up/down market details screen
    Then the vertical space above and below the time-slot selector is equal

  Scenario: Separator dot is centered in a position row
    Given I am on a crypto up/down market details screen
    And I hold at least one position in the series
    Then the dot between the outcome label and the entry price is vertically centered

  Scenario: No payout preview under the buy buttons and chart fills the space
    Given I am on a crypto up/down market details screen
    Then no "$100 -> $..." payout estimate is shown under the Up and Down buttons
    And the price chart uses the freed space above the sticky action buttons

  Scenario: First position visible and the rest scroll
    Given I am on a crypto up/down market details screen
    And I hold more positions than fit on screen
    Then the first position row is visible above the sticky action buttons
    And the remaining position rows are reachable by scrolling
```

## **Screenshots/Recordings**

### **Before**

N/A — author to attach device capture before marking Ready for review
(changes are visual layout tweaks on the crypto up/down details screen
that need a simulator/device to record).

### **After**

N/A — author to attach device capture before marking Ready for review.

## **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
- [x] I've included tests if applicable
- [x] 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.

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **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]
> **Low Risk**
> Predict UI-only changes in TimeSlotPicker and crypto up/down details;
scroll logic is covered by new tests with no auth or data-path impact.
> 
> **Overview**
> Fixes **Predict crypto up/down** layout and **TimeSlotPicker** scroll
behavior when a live slot rolls off.
> 
> **Time slot picker:** When the live pill disappears and the list
shifts left, horizontal scroll no longer drifts off the left edge. Stale
`pillPositions` entries are pruned, anchoring re-runs on `marketsKey`
changes, and the selected pill’s `onLayout` re-scrolls immediately so a
50ms timer doesn’t win a race against re-layout. Regression tests cover
initial anchor and post-expiry re-anchor.
> 
> **Details screen polish:** Price-summary top padding is tightened
(`pt-5` → `pt-3`) so spacing above/below the picker matches. With
positions, the chart grows (ratio **0.44**, max **430px**) after
dropping the buy-button payout estimate (`showPayoutEstimate` no longer
passed). **Position rows:** the `·` separator is its own `Text` node for
better vertical alignment with the outcome/entry labels.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8308aa7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
runway-github Bot added a commit that referenced this pull request Jun 9, 2026
… expires cp-7.81.0 (#31231)

## **Description**

This PR bundles four UI/behavior fixes on the Predict **crypto up/down**
details screen (plus one shared positions tweak). All changes are
confined to `app/components/UI/Predict/`.

**1. Time-slot picker loses its left anchor when the live slot expires
(primary fix)**
When the live time slot expired and rolled to the next window, the
horizontal `TimeSlotPicker` no longer kept the live/selected pill
anchored at the left. Root cause: the auto-scroll read pill
x-coordinates from a cached `pillPositions` map that (1) retained stale
entries for markets that had been filtered out, and (2) was read by a
fixed 50ms settle timer that raced ahead of React Native's async
re-layout — so `scrollTo` used the pre-shift offset and over-scrolled.
- Prune `pillPositions` to only currently-rendered markets whenever
`markets` changes.
- Re-run the settle-delay anchor on the ordered `marketsKey` so a left
shift re-anchors even when the resolved selection is unchanged.
- Re-anchor immediately when the selected pill reports a new layout `x`,
beating the timer/layout race.
- Adds a regression test that reproduces the expiry race (verified
failing pre-fix, passing post-fix).

**2. Even spacing around the time-slot picker**
The picker is a flush `h-11` container with no vertical padding of its
own, so the gap above (title `pb-3` = 12px) and below (price summary
`pt-5` = 20px) were uneven. Changed the price-summary top padding `pt-5
→ pt-3` so the picker has equal 12px above and below.

**3. Centered separator dot in positions rows**
The `Up/Down · entry` separator dot was baseline-glued to the entry
label via a `' · '` string, so it sat slightly off-center. Split it into
its own `Text` node so it aligns optically in the center-aligned row.

**4. Remove the `$100 → $X` payout preview from the up/down CTA + grow
the chart**
Removed the payout estimate under the buy buttons on the crypto up/down
details page by no longer passing `showPayoutEstimate` to the shared
`PredictMarketDetailsActions`. The prop, formatter, and gated rendering
remain intact on that component for any other surface that wants the
preview (none currently enable it), so the change is regression-safe.
The freed vertical space is reclaimed by growing the with-positions
chart height (ratio `0.4 → 0.44`, max `380 → 430`) so the chart fills
the gap above the sticky actions while keeping the first position row
visible and the rest scrollable.

## **Changelog**

CHANGELOG entry: Fixed the Predict crypto up/down time-slot selector so
the live slot stays anchored to the left when it rolls to the next
window, evened out the spacing around the selector, and removed the
payout estimate from the buy buttons to give the price chart more room.

## **Related issues**

Refs: No external ticket — incremental UX polish on the Predict crypto
up/down details screen reported during QA review (live-slot scroll
anchoring regression, uneven selector spacing, off-center separator dot,
payout-preview removal + chart sizing).

## **Manual testing steps**

```gherkin
Feature: Predict crypto up/down details screen

  Scenario: Live time slot stays anchored left when it expires
    Given I am on a crypto up/down market details screen
    And the live time slot is the left-most pill in the selector
    When the live slot expires and the next slot becomes live
    Then the new live slot is anchored to the left edge of the selector
    And the selector is not over-scrolled or visually shifted

  Scenario: Time-slot selector is evenly spaced
    Given I am on a crypto up/down market details screen
    Then the vertical space above and below the time-slot selector is equal

  Scenario: Separator dot is centered in a position row
    Given I am on a crypto up/down market details screen
    And I hold at least one position in the series
    Then the dot between the outcome label and the entry price is vertically centered

  Scenario: No payout preview under the buy buttons and chart fills the space
    Given I am on a crypto up/down market details screen
    Then no "$100 -> $..." payout estimate is shown under the Up and Down buttons
    And the price chart uses the freed space above the sticky action buttons

  Scenario: First position visible and the rest scroll
    Given I am on a crypto up/down market details screen
    And I hold more positions than fit on screen
    Then the first position row is visible above the sticky action buttons
    And the remaining position rows are reachable by scrolling
```

## **Screenshots/Recordings**

### **Before**

N/A — author to attach device capture before marking Ready for review
(changes are visual layout tweaks on the crypto up/down details screen
that need a simulator/device to record).

### **After**

N/A — author to attach device capture before marking Ready for review.

## **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
- [x] I've included tests if applicable
- [x] 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.

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **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]
> **Low Risk**
> Predict UI-only changes in TimeSlotPicker and crypto up/down details;
scroll logic is covered by new tests with no auth or data-path impact.
>
> **Overview**
> Fixes **Predict crypto up/down** layout and **TimeSlotPicker** scroll
behavior when a live slot rolls off.
>
> **Time slot picker:** When the live pill disappears and the list
shifts left, horizontal scroll no longer drifts off the left edge. Stale
`pillPositions` entries are pruned, anchoring re-runs on `marketsKey`
changes, and the selected pill’s `onLayout` re-scrolls immediately so a
50ms timer doesn’t win a race against re-layout. Regression tests cover
initial anchor and post-expiry re-anchor.
>
> **Details screen polish:** Price-summary top padding is tightened
(`pt-5` → `pt-3`) so spacing above/below the picker matches. With
positions, the chart grows (ratio **0.44**, max **430px**) after
dropping the buy-button payout estimate (`showPayoutEstimate` no longer
passed). **Position rows:** the `·` separator is its own `Text` node for
better vertical alignment with the outcome/entry labels.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8308aa7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
runway-github Bot pushed a commit that referenced this pull request Jun 9, 2026
…ed left when live slot expires cp-7.81.0 (#31231)

## **Description**

This PR bundles four UI/behavior fixes on the Predict **crypto up/down**
details screen (plus one shared positions tweak). All changes are
confined to `app/components/UI/Predict/`.

**1. Time-slot picker loses its left anchor when the live slot expires
(primary fix)**
When the live time slot expired and rolled to the next window, the
horizontal `TimeSlotPicker` no longer kept the live/selected pill
anchored at the left. Root cause: the auto-scroll read pill
x-coordinates from a cached `pillPositions` map that (1) retained stale
entries for markets that had been filtered out, and (2) was read by a
fixed 50ms settle timer that raced ahead of React Native's async
re-layout — so `scrollTo` used the pre-shift offset and over-scrolled.
- Prune `pillPositions` to only currently-rendered markets whenever
`markets` changes.
- Re-run the settle-delay anchor on the ordered `marketsKey` so a left
shift re-anchors even when the resolved selection is unchanged.
- Re-anchor immediately when the selected pill reports a new layout `x`,
beating the timer/layout race.
- Adds a regression test that reproduces the expiry race (verified
failing pre-fix, passing post-fix).

**2. Even spacing around the time-slot picker**
The picker is a flush `h-11` container with no vertical padding of its
own, so the gap above (title `pb-3` = 12px) and below (price summary
`pt-5` = 20px) were uneven. Changed the price-summary top padding `pt-5
→ pt-3` so the picker has equal 12px above and below.

**3. Centered separator dot in positions rows**
The `Up/Down · entry` separator dot was baseline-glued to the entry
label via a `' · '` string, so it sat slightly off-center. Split it into
its own `Text` node so it aligns optically in the center-aligned row.

**4. Remove the `$100 → $X` payout preview from the up/down CTA + grow
the chart**
Removed the payout estimate under the buy buttons on the crypto up/down
details page by no longer passing `showPayoutEstimate` to the shared
`PredictMarketDetailsActions`. The prop, formatter, and gated rendering
remain intact on that component for any other surface that wants the
preview (none currently enable it), so the change is regression-safe.
The freed vertical space is reclaimed by growing the with-positions
chart height (ratio `0.4 → 0.44`, max `380 → 430`) so the chart fills
the gap above the sticky actions while keeping the first position row
visible and the rest scrollable.

## **Changelog**

CHANGELOG entry: Fixed the Predict crypto up/down time-slot selector so
the live slot stays anchored to the left when it rolls to the next
window, evened out the spacing around the selector, and removed the
payout estimate from the buy buttons to give the price chart more room.

## **Related issues**

Refs: No external ticket — incremental UX polish on the Predict crypto
up/down details screen reported during QA review (live-slot scroll
anchoring regression, uneven selector spacing, off-center separator dot,
payout-preview removal + chart sizing).

## **Manual testing steps**

```gherkin
Feature: Predict crypto up/down details screen

  Scenario: Live time slot stays anchored left when it expires
    Given I am on a crypto up/down market details screen
    And the live time slot is the left-most pill in the selector
    When the live slot expires and the next slot becomes live
    Then the new live slot is anchored to the left edge of the selector
    And the selector is not over-scrolled or visually shifted

  Scenario: Time-slot selector is evenly spaced
    Given I am on a crypto up/down market details screen
    Then the vertical space above and below the time-slot selector is equal

  Scenario: Separator dot is centered in a position row
    Given I am on a crypto up/down market details screen
    And I hold at least one position in the series
    Then the dot between the outcome label and the entry price is vertically centered

  Scenario: No payout preview under the buy buttons and chart fills the space
    Given I am on a crypto up/down market details screen
    Then no "$100 -> $..." payout estimate is shown under the Up and Down buttons
    And the price chart uses the freed space above the sticky action buttons

  Scenario: First position visible and the rest scroll
    Given I am on a crypto up/down market details screen
    And I hold more positions than fit on screen
    Then the first position row is visible above the sticky action buttons
    And the remaining position rows are reachable by scrolling
```

## **Screenshots/Recordings**

### **Before**

N/A — author to attach device capture before marking Ready for review
(changes are visual layout tweaks on the crypto up/down details screen
that need a simulator/device to record).

### **After**

N/A — author to attach device capture before marking Ready for review.

## **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
- [x] I've included tests if applicable
- [x] 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.

#### Performance checks (if applicable)

- [x] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **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]
> **Low Risk**
> Predict UI-only changes in TimeSlotPicker and crypto up/down details;
scroll logic is covered by new tests with no auth or data-path impact.
> 
> **Overview**
> Fixes **Predict crypto up/down** layout and **TimeSlotPicker** scroll
behavior when a live slot rolls off.
> 
> **Time slot picker:** When the live pill disappears and the list
shifts left, horizontal scroll no longer drifts off the left edge. Stale
`pillPositions` entries are pruned, anchoring re-runs on `marketsKey`
changes, and the selected pill’s `onLayout` re-scrolls immediately so a
50ms timer doesn’t win a race against re-layout. Regression tests cover
initial anchor and post-expiry re-anchor.
> 
> **Details screen polish:** Price-summary top padding is tightened
(`pt-5` → `pt-3`) so spacing above/below the picker matches. With
positions, the chart grows (ratio **0.44**, max **430px**) after
dropping the buy-button payout estimate (`showPayoutEstimate` no longer
passed). **Position rows:** the `·` separator is its own `Text` node for
better vertical alignment with the outcome/entry labels.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8308aa7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 9, 2026
@metamaskbotv2 metamaskbotv2 Bot added the release-7.82.0 Issue or pull request that will be included in release 7.82.0 label Jun 9, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.82.0 Issue or pull request that will be included in release 7.82.0 risk:low AI analysis: low risk size-M team-predict Predict team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants