fix(app): preserve mobile sidebar scroll position when reopening (#6058)

* fix(app): preserve mobile sidebar scroll position when reopening

Keep hidden native overlays laid out so Android touch cancellation cannot spring retained scroll offsets through a zero scroll range. Hide and gate touch input on the UI thread to preserve panel motion during JS stalls.

* docs(app): quote sidebar replay workspace examples

* test(website): read plugin HTML without waiting for remote images

* test(website): exercise built worker in browser checks

The ordered plugin spec reproduces a no-response navigation timeout against a cold development server. Build and preview the published worker for E2E checks; preserve the original content and metadata assertions.
This commit is contained in:
Mohamed Boudra
2026-10-04 14:55:24 +01:00
committed by GitHub
parent 05b074764d
commit 30fb66c8cb
6 changed files with 92 additions and 8 deletions
+4 -2
View File
@@ -32,8 +32,10 @@ The UI worklet owns transient motion:
React publishes the active panel only when the canonical target and the UI-thread position agree at
the final anchor. Retained content never observes gesture previews, progress, or an unsettled target.
The gesture hosts stay mounted; worklets reveal their retained overlays through native styles while
React owns pointer events and accessibility. Native panel hosts and their dependent draggable lists
The gesture hosts stay mounted. Native worklets own overlay opacity and pointer events while
React owns settled panel activity and accessibility. Keep hidden native overlays laid out: collapsing
their scroll ranges makes Android spring retained offsets back to zero during touch cancellation or
release. Native panel hosts and their dependent draggable lists
also retain identity across appearance hydration and settings changes. Do not wrap those hosts in
appearance keys; see [Unistyles appearance boundaries](unistyles.md#runtime-theme-patching-for-user-preferences).
+20
View File
@@ -65,6 +65,26 @@ Metro, and device through the `PASEO_COMPOSER_KEYBOARD_*` variables in
the headless input helper cannot verify the
[visible composer constraints](floating-panels.md#gotcha-3--keyboard-layout-and-portal-anchors).
The Android sidebar scroll-retention flow requires a connected host with enough
workspaces to overflow the compact sidebar. Pass `TOP_WORKSPACE` and
`SCROLLED_WORKSPACE` as the `serverId:workspaceId` suffixes of their sidebar row
IDs. Choose one row near the top and one initially below the viewport. Replace
the quoted example values below with those IDs. Start in a workspace with the
sidebar closed and keep the list stable during the run. The same flow checks
reopening by swipe and button:
```bash
agent-device replay packages/app/e2e/mobile/agent-device/native-sidebar-scroll-retention.android.yaml \
--maestro --platform android --serial emulator-5556 --metro-port 8099 \
--env TOP_WORKSPACE='server-id:top-workspace-id' \
--env SCROLLED_WORKSPACE='server-id:scrolled-workspace-id'
```
Pass this checkout's Metro port so the debug app uses the intended bundle.
For iOS, compare the scrolled row's screen bounds and screenshots across reopening.
Agent Device's iOS visibility lookup includes offscreen scroll descendants, so
its `assertNotVisible` cannot establish the starting scroll position for this flow.
On a Play-image emulator, disable Gmail and Calendar first. Their welcome
screens launch on their own, take input focus, and the run fails with
`IME did not become visible` while the app still looks focused: