Skip to content

fix(mobile): make swipe back smoother - #1793

Merged
ocavue merged 36 commits into
masterfrom
ocavuebot/back-pager
Nov 2, 2026
Merged

ocavue merged 36 commits into
masterfrom
ocavuebot/back-pager

Conversation

@ocavuebot

@ocavuebot ocavuebot commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Makes the native scroll-snap pager the mobile edge back swipe and deletes the pointer-driven one. There is no flag and no second path.

What changed

  • MobileStack renders its layers as pages of a scroll-snap-type: x mandatory scroller. Every page is position: sticky; left: 0 and the current page is last, so a swipe moves only the current card while the page below stays put. useBackPager pins scrollLeft to the last page before paint whenever the page list changes, and on resize.
  • Stacked screens get touch-action: pan-y through a zero-specificity rule in @layer base. A 20px full-height edge strip (data-pager-edge, touch-action: pan-x) is the only place where a horizontal drag reaches the pager. Horizontal scrollers carry data-scroll-x (meowdown sets it on code blocks and math and Mermaid previews, feat: mark horizontal scrollers with data-scroll-x prosekit/meowdown#752, released in 0.82.3; swipe rows set it too), and they and everything inside them opt back into auto with overscroll-behavior-x: contain.
  • A tap on the strip goes to what lies under it (elementsFromPoint and caretRangeFromPoint with the strip's pointer events off): fields focus, controls click, and the editor gets a caret.
  • watchScrollSettle commits the pop when a user scroll settles at scrollLeft <= 1. The revealed page drops inert and aria-hidden at once, before React re-renders it as current. A scroll that no finger, wheel, or mouse drag started pins the pager back.
  • A mouse drag works like a finger, but only from the edge strip (dragHandle). A plain click on the strip still forwards; the click that ends a drag does not.
  • The gesture scrim follows the scroll through linkOpacityToScroll. Button back, wiki-link push, and other programmatic push and pop keep the existing CSS keyframes.
  • The component doc comment states the stacked-screen rules: no position: fixed element inside a stacked screen (it would stay put while the card moves), and data-scroll-x for any horizontal scroller.

What was deleted

  • mobile/use-back-swipe.ts and its test (the pointer hook with its non-passive touchmove blocker, per-move setState, and settle transition).
  • The pointer render path in mobile-stack.tsx: the dragging and settling styles, the drag scrim, and the transitionend listener.
  • The four pointer back-swipe tests. The push, pop, tab, note-chain, and reduced-motion tests now run once, on the pager. lib/pointer-drag.ts stays (the image dismiss drag uses it).

What users feel

  • The card follows the finger on the compositor, so a busy main thread (a long note mounting, a sync batch, a save) no longer freezes the card mid-swipe. React does not render during the drag.
  • The commit point is the native snap: about half the width, or a fling. The old 40% distance and velocity rule is gone.
  • A swipe that starts anywhere but the left 20px scrolls the note vertically and never goes back. Horizontal scrolling inside notes keeps working.
  • A snap back can be caught by a new touch; the old settle transition could not.
  • Known limitation: a vertical drag that starts in the leftmost 20px (the edge strip) does not scroll the screen. The strip is a sibling of the screen's scroller, not its ancestor, so the drag cannot chain into it. Start a vertical drag anywhere else to scroll.

Before and after

Chromium 156.0.8078.4 (Playwright, headless, isMobile, 390x844), 4x CPU throttle, dev build, n = 7 per row after 1 warmup. Base b83dca13 (old hook; the old path is byte-identical at the PR's base 26f9058a), PR 9764ce22. Real CDP Input.dispatchTouchEvent gestures from (8, 420): pop = slow drag to x 330 and release; cancel = drag to x 100, hold 300ms, release; fling = 5 moves to x 150, 8ms apart. Light note: notes/sarah-chen.md (seed). Heavy note: a generated 3000-line note. "During" is touchStart to touchEnd; "after" is the 1.5s after touchEnd. LoAF max is the max over reps; other columns are p50. Script and task time come from CDP Performance.getMetrics deltas over the drag, divided by the delivered touchmove count. p95FrameMs and hitchTimeRatio use the perf HUD formula on rAF times from touchStart to touchEnd + 500ms. Correct means the expected outcome happened exactly once (one back() for a pop, none for a cancel).

note, gesture build LoAF max during (ms) LoAF total after (ms) React commits during drag script ms / move task ms / move p95FrameMs hitchTimeRatio correct
light pop base 0 55 21 1.94 4.43 16.8 11.5 7/7
light pop PR 0 0 0 0.10 1.35 16.8 13.9 7/7
heavy pop base 57 89 21 1.92 8.90 16.8 45.2 7/7
heavy pop PR 0 78 0 0.16 9.42 16.8 54.2 7/7
light cancel base 0 0 18 1.97 5.02 16.8 0.4 7/7
light cancel PR 0 0 0 0.13 1.57 16.8 11.2 7/7
heavy cancel base 0 0 18 2.04 11.00 16.8 18.7 7/7
heavy cancel PR 0 0 0 0.20 15.62 16.8 11.1 7/7
light fling base 0 52 6 2.42 7.37 16.7 23.4 7/7
light fling PR 0 0 0 0.19 2.16 16.7 0.3 7/7
heavy fling base 59 85 6 2.41 24.16 16.8 85.2 7/7
heavy fling PR 0 79 0 0.25 14.75 16.7 0.3 7/7
  • Script time per move drops about 10x and React commits during the drag drop to 0. LoAFs during the drag are gone.
  • The heavy note still costs main-thread task time (style, layout, paint) while it scrolls, and the pop still has one LoAF of about 80ms after release (the revealed daily re-render). The pager moves the drag off the main thread; it does not make the commit cheaper.
  • rAF metrics only describe the main thread. In Chromium they stay at the frame budget in both builds; they do not show compositor smoothness.
  • One behavior difference: a slow drag to x 100 released while the finger still moves (no hold) pops 7/7 with the pager and cancels 7/7 with the old hook. Chromium snaps a fling to the next snap point in its direction. WebKit on iOS may differ; check it on a device.

How to test by hand

On an iPhone (or iPad) build, open a note from Daily:

  1. Swipe right from the left edge past half and release: the note goes back to Daily. Swipe partway, stop, release: the note stays.
  2. Flick quickly from the left edge: it goes back. Start a new touch while the card snaps back: the card follows the finger again.
  3. Swipe right from the middle of the note: nothing goes back; vertical scrolling stays smooth. Diagonal drags scroll vertically.
  4. Tap near the left edge: the Back button (its left part sits under the strip), a text field, and the start of a text line still work (the caret lands at the line start).
  5. Scroll a wide code block, a table, a math or Mermaid preview sideways: it scrolls, and dragging past its left end does not go back.
  6. Repeat 1 in Settings, Graphs, Licenses, a note-to-note chain (lands on the previous note), and a cold note entry (lands on today).
  7. With a mouse or trackpad pointer (iPad or desktop browser at ?platform=ios): press on the left 20px and drag right: it goes back. Click the strip over the Back button: it goes back once. Drag on note text: it selects text and never swipes.
  8. Turn on Reduce Motion: button back and push are instant; the swipe still works.
  9. On a long note or Settings, drag vertically starting inside the leftmost 20px: the screen does not scroll (known limitation). The same drag starting further right scrolls normally.

Written by Claude Opus 5.5.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

View guided diff Turn on auto-fix

Summary by Sourcery

Adopt native scroll-snap paging for mobile edge back navigation to improve gesture responsiveness and preserve nested scrolling and underlying interactions.

New Features:

  • Replace the mobile pointer-driven back swipe with a native scroll-snap pager for edge back navigation, including touch and mouse gestures.
  • Preserve interaction with controls, fields, editors, and horizontal scrollers beneath the edge gesture strip.

Bug Fixes:

  • Prevent unintended back navigation from non-edge gestures, programmatic scrolls, and horizontal scrolling within note content.
  • Ensure the revealed screen becomes interactive immediately when a swipe pop settles.

Enhancements:

  • Move swipe progress and settling to browser scrolling so React does not render during the gesture and the pager remains responsive under main-thread load.
  • Retain existing programmatic navigation animations while simplifying stack-layer transitions and gesture handling.

Documentation:

  • Document mobile stacked-screen constraints and requirements for fixed elements and horizontal scrollers.

Tests:

  • Update mobile navigation coverage for native pager swipes, cancellation, settling, resizing, mouse gestures, tap forwarding, and note navigation scenarios.

Chores:

  • Remove the pointer-based back-swipe hook and its dedicated tests.

Summary by CodeRabbit

  • New Features
    • Mobile navigation now supports edge-to-edge back swipes using horizontal page scrolling. A narrow edge area also lets you tap underlying fields and controls while navigating stacked screens.
  • Bug Fixes
    • Back navigation now handles touch and mouse gestures more consistently, including quick swipes, interrupted gestures, and late scrolling events. Scrolling within mobile pages remains vertical by default, while designated horizontal content can still scroll sideways.

@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4e254b4a-f7bf-45ec-b7de-a81d1bcd1751
Commits

Reviewing files that changed from the base of the PR and between f7211f4 and 8b21d18.

Files selected for processing: 7
  • apps/desktop/src/mobile/mobile-screen.test.tsx
  • apps/desktop/src/mobile/mobile-stack.tsx
  • apps/desktop/src/mobile/use-back-pager.ts
  • apps/desktop/src/mobile/use-back-swipe.test.tsx
  • apps/desktop/src/mobile/use-back-swipe.ts
  • apps/desktop/src/styles/index.css
  • docs/porting/reflect-mobile/app-shell-and-navigation.md
Files with no reviewable changes: 2
  • apps/desktop/src/mobile/use-back-swipe.test.tsx
  • apps/desktop/src/mobile/use-back-swipe.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.

Walkthrough

Mobile stack navigation replaces pointer-driven back-swipe handling with a horizontal scroll-snap pager. A new hook manages pager positioning and scroll settling. Stack rendering, touch-action styling, interaction tests, and porting notes now reflect the pager.

Changes

Mobile back pager

Layer / File(s) Summary
Pager scroll and pop behavior
apps/desktop/src/mobile/use-back-pager.ts, apps/desktop/src/mobile/use-back-swipe.ts, apps/desktop/src/mobile/use-back-swipe.test.tsx
Adds useBackPager to position pages and handle settled user scrolls. A qualifying scroll reveals the lower page and calls the pop callback. Removes the previous swipe hook and its listener tests.
Pager integration and navigation
apps/desktop/src/mobile/mobile-stack.tsx, apps/desktop/src/styles/index.css, docs/porting/reflect-mobile/app-shell-and-navigation.md
Renders stack layers as scroll-snap pages and connects gesture pops to navigation. Adds pager touch-action rules and updates the porting notes.
Pager interaction tests
apps/desktop/src/mobile/mobile-screen.test.tsx
Tests pager position, touch and mouse gestures, edge-strip taps, and navigation between stacked and cold-note routes.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Pager
  participant useBackPager
  participant MobileStack
  User->>Pager: Scroll toward the lower page
  Pager->>useBackPager: Report scroll settling
  useBackPager->>Pager: Reveal lower page at offset at or below 1 px
  useBackPager->>MobileStack: Call onPop
  MobileStack->>MobileStack: Call back or navigate to today
Loading
Merge Risk: Low · up to 8b21d

A canceled swipe can unexpectedly navigate back, and a resize during a drag can make the page jump. Both are bounded gesture issues, but they should be fixed or explicitly accepted before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly describes the main change: improving mobile swipe-back behavior. It is concise and directly related to the native scroll pager implementation.
Full details: Docstring Coverage

Explanation

Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 6 functions across 3 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@sourcery-ai

sourcery-ai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Migrates mobile edge back navigation from React-driven pointer gestures to a compositor-friendly native scroll-snap pager, adding precise gesture routing for nested scrolling and taps, settle-time accessibility handling, mouse support, documentation, and comprehensive updated tests.

Sequence diagram for a mobile edge swipe pop

sequenceDiagram
    actor User
    participant Edge as EdgeStrip
    participant Pager as NativePager
    participant Settle as watchScrollSettle
    participant Below as RevealedPage
    participant Router

    User->>Edge: Start and drag horizontally
    Edge->>Pager: Allow native horizontal scroll
    Pager->>Pager: Snap to lower page
    Pager->>Settle: Report settled scroll
    Settle->>Below: Remove inert and aria-hidden
    Settle->>Router: onPop()
    Router-->>Pager: Re-render stack
    Pager->>Pager: Pin scrollLeft to last page
Loading

Flow diagram for mobile gesture routing

flowchart TD
    Start[Gesture or tap in mobile screen]
    Edge{Starts in left 20px edge strip?}
    Horizontal{Inside data-scroll-x scroller?}
    Vertical[Allow vertical pan]
    Pager[Route horizontal drag to native pager]
    Tap[Forward tap through strip]
    Target[Focus field, click control, or place editor caret]

    Start --> Edge
    Edge -->|no| Vertical
    Edge -->|yes| Horizontal
    Horizontal -->|yes| Vertical
    Horizontal -->|no horizontal drag| Pager
    Horizontal -->|tap| Tap
    Tap --> Target
Loading

File-Level Changes

Change Details Files
Replace pointer-driven mobile back swipes with a native horizontal scroll-snap pager and settle-driven navigation.
  • Render stack layers as sticky snap pages in a horizontal scroller, pinning the current page before paint and on resize.
  • Commit a pop only after a user-initiated scroll settles on the revealed page; reveal the underlying layer before navigation re-renders.
  • Link scrim opacity directly to scroll position and retain CSS keyframes for programmatic transitions.
  • Support edge-strip mouse drags while rejecting non-user scrolls and preventing duplicate commits.
apps/desktop/src/mobile/mobile-stack.tsx
apps/desktop/src/mobile/use-back-pager.ts
Constrain gesture hit-testing so edge back navigation coexists with vertical page scrolling, nested horizontal scrolling, and taps.
  • Apply vertical-only touch handling to stacked screens and opt horizontal scrollers into native horizontal gestures with contained overscroll.
  • Limit horizontal drag initiation to a 20px edge strip and forward strip taps to fields, controls, or editable content underneath.
  • Document stacked-screen constraints, including avoiding position-fixed descendants and marking horizontal scrollers with data-scroll-x.
apps/desktop/src/styles/index.css
apps/desktop/src/mobile/mobile-stack.tsx
docs/porting/reflect-mobile/app-shell-and-navigation.md
Rewrite mobile navigation tests around native pager behavior and remove the legacy pointer-swipe implementation.
  • Cover native scroll settling, cancellation, duplicate-event protection, reveal timing, cold entries, note chains, mouse drags, and edge tap forwarding.
  • Remove pointer-event and transition-end test helpers and legacy back-swipe tests.
  • Delete the pointer-based back-swipe hook while retaining unrelated pointer-drag functionality.
apps/desktop/src/mobile/mobile-screen.test.tsx
apps/desktop/src/mobile/use-back-swipe.ts
apps/desktop/src/mobile/use-back-swipe.test.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@ocavuebot
ocavuebot force-pushed the ocavuebot/back-pager branch from 8731ad0 to 0fb1dc9 Compare October 30, 2026 09:54
@ocavuebot
ocavuebot force-pushed the ocavuebot/back-pager branch from 0fb1dc9 to c69bd03 Compare October 30, 2026 10:00
@ocavuebot
ocavuebot force-pushed the ocavuebot/back-pager branch from c69bd03 to 9764ce2 Compare October 30, 2026 10:15
@ocavuebot ocavuebot changed the title feat(mobile): add a native scroll back swipe behind a debug switch fix(mobile): swipe back with native scroll Oct 30, 2026
@ocavuebot
ocavuebot force-pushed the ocavuebot/back-pager branch from 9764ce2 to cb9e434 Compare October 30, 2026 10:39
Base automatically changed from ocavuebot/native-scroll-helpers to master October 30, 2026 11:02
# Conflicts:
#	apps/desktop/src/lib/scroll-settle.ts
@ocavue
ocavue marked this pull request as ready for review November 2, 2026 15:24
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

# Conflicts:
#	apps/desktop/src/mobile/mobile-screen.test.tsx

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="apps/desktop/src/mobile/mobile-screen.test.tsx" line_range="979-983" />
<code_context>
-    const stack = view.container.querySelector('.mobile-stack')!
-    const card = stackLayers(view).at(-1)!
+    const scroller = pager(view)
+    await mouseDragFromStrip(view, 60)
+    await waitFor(() => expect(scroller.scrollLeft).toBe(scroller.clientWidth))
+    await new Promise((resolve) => setTimeout(resolve, 200))
+    expect(view.getByRole('heading').element().textContent).toBe('Edit note')
+    expect(stackLayers(view)).toHaveLength(2)
+  })

</code_context>
<issue_to_address>
**Ignored mouse drags pass snap-back test**

When the mouse-drag path ignores a short drag but does not forward its click, `it('snaps a short mouse drag back without passing its click to the back button')` only checks that the note remains visible and the pager ends at its starting offset. A handler that ignores the drag but suppresses its click passes without ever scrolling or snapping back.

Assert that the pager moves during the drag before verifying that it returns to the last page.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

@ocavuebot ocavuebot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent review by Claude (model ID: claude-opus-5-5) at 8b21d18e282d43fd88d473bb79532b22bc139437.

Summary:

  1. Simplification (inline, use-back-pager.ts:41): pageCount is not needed. "Last page" is the end of the scroll range.
  2. Possible logic bug (inline, use-back-pager.ts:116): the resize re-pin ignores a finger that is down. The drawer in #1794 guards this case.
  3. Question: watchScrollSettle counts a wheel as a user scroll, and touch-action does not apply to wheel input. So on an iPad with a trackpad (or in the browser preview), a two-finger horizontal scroll anywhere on a stacked screen moves the pager, and a long one pops. The PR text says only the edge strip starts a back swipe. If this is intended (iPadOS has a trackpad back swipe), please write it in the PR text. If not, ignore a wheel for the pop.
  4. Edge case (no action needed if accepted): forwardStripTap only focuses an input. A checkbox or radio input under the 20px strip gets focus but does not toggle. Long press (text selection, link preview) is also lost under the strip. Both are probably fine trade-offs, but the PR text does not list them.

@ocavue ocavue left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI model ID: gpt-6 (Codex).
Reviewed commit: 8b21d18e282d43fd88d473bb79532b22bc139437.

Independent source review of the pager, stack, CSS, and settlement helper. No local tests or device checks were run.

[P2, known behavior trade-off] The edge strip removes vertical scrolling from the leftmost 20px. At apps/desktop/src/mobile/mobile-stack.tsx:387, the full-height strip receives the gesture and allows only horizontal panning. A vertical drag starting there cannot scroll a long note or Settings. I read the existing response: changing it to pan-x pan-y alone cannot fix this, because the content scroller is a sibling. This is a real UX regression that the current architecture accepts, not a missing defensive guard. Please make that limitation explicit in the PR's user-facing behavior and manual checks. If preserving edge vertical scrolling is required, the hit region needs to participate in the content scroller's ancestor chain, or needs deliberate gesture forwarding.

Simplification recommendation: keep the synthetic tap forwarding narrowly scoped. It already reconstructs clicks, field focus, and editor caret placement, but cannot preserve the full native pointer interaction. Avoid extending it into a general input dispatcher with more target-specific fallbacks. Resolve the hit-region layout first if more edge interactions must work.

I found no additional high-confidence navigation-state bug in the current diff. The once-only pop guard and programmatic-scroll rejection serve concrete purposes; I would retain them.

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Fix comments: Fix CodeRabbit comments on this PR

@ocavuebot

Copy link
Copy Markdown
Collaborator Author

Before/after recording with Chrome CPU throttling at 20x (Emulation.setCPUThrottlingRate), with ?perf on so the frame-rate HUD is in the picture. Left: master. Right: this PR.

Gestures (CDP touch events, 390x844 viewport), two rounds:

  1. Tap "Sarah Chen" in the All list to open the note.
  2. Slow drag from the left edge to x = 330: goes back.
  3. Open the note again.
  4. Short drag to x = 100, hold 300 ms, release: snaps back and stays on the note.
  5. Quick flick from the left edge to x = 150: goes back.
a3_cpu20_base_vs_pr.mp4

# Conflicts:
#	apps/desktop/src/mobile/mobile-stack.tsx
@ocavuebot ocavuebot changed the title fix(mobile): swipe back with native scroll fix(mobile): make swipe back smoother Nov 2, 2026
@ocavue
ocavue merged commit c224cb4 into master Nov 2, 2026
17 checks passed
@ocavue
ocavue deleted the ocavuebot/back-pager branch November 2, 2026 16:38
This was referenced Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants