From d77d13f23b468d50585aaba1fd1b5ed3b8395e73 Mon Sep 17 00:00:00 2001 From: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Date: Wed, 20 May 2026 11:29:38 +0800 Subject: [PATCH] fix(mobile): cold-start anchor for formSheet deep links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without unstable_settings.anchor, a deep link or notification that targets a formSheet route (issue/[id]/picker/status, etc.) cold-starts the app onto the sheet alone — no parent screen, swipe-down lands the user on a blank canvas. Anchor: '(tabs)' tells Expo Router to mount the tab UI as the implicit base, so dismissing the sheet always returns to a sensible workspace home. Set on the workspace _layout.tsx that owns every formSheet route registration. The root (app)/_layout has no formSheet declarations so no anchor is needed there. --- apps/mobile/app/(app)/[workspace]/_layout.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/mobile/app/(app)/[workspace]/_layout.tsx b/apps/mobile/app/(app)/[workspace]/_layout.tsx index 9a5a67462..d98c2dd72 100644 --- a/apps/mobile/app/(app)/[workspace]/_layout.tsx +++ b/apps/mobile/app/(app)/[workspace]/_layout.tsx @@ -44,6 +44,17 @@ const SHEET_OPTIONS: ComponentProps["options"] = { headerShown: false, }; +/** + * Cold-start deep-link anchor. Expo Router otherwise treats whatever + * route resolves the URL as the root of the stack — if the user opens a + * notification that targets `issue/[id]/picker/status` directly, they + * land on the formSheet with NO parent under it, no way to go back to + * the tabs. `anchor: "(tabs)"` tells the router to mount the tab UI as + * the implicit underlying screen so back/swipe-dismiss returns the user + * to a sensible base state. + */ +export const unstable_settings = { anchor: "(tabs)" } as const; + /** * Mounts every per-feature realtime subscription. Lives inside * RealtimeProvider so the WSClient context is available, and stays alive