diff --git a/apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz b/apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz
deleted file mode 100644
index ee21d1ffd5c1f15a57326e2508665bcf8050ebb0..0000000000000000000000000000000000000000
Binary files a/apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz and /dev/null differ
diff --git a/apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz b/apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..4aa9184ac209e0c7085265ff9b5f4717efc39fdd
Binary files /dev/null and b/apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz differ
diff --git a/apps/mobile/package.json b/apps/mobile/package.json
index c4175c317d3b426f85b9da9444f7fcc4656069f2..c7067dfc1e0aa3fae82e43063396414c3970a6c6 100644
--- a/apps/mobile/package.json
+++ b/apps/mobile/package.json
@@ -126,7 +126,7 @@
"react-native-keyboard-controller": "1.22.6",
"react-native-reanimated": "4.7.0",
"react-native-safe-area-context": "~5.9.1",
- "react-native-screens": "file:deps/react-native-screens-5.0.0-t3.26.tgz",
+ "react-native-screens": "file:deps/react-native-screens-5.0.0-t3.27.tgz",
"react-native-shiki-engine": "^0.3.12",
"react-native-svg": "15.15.5",
"react-native-webview": "14.0.1",
diff --git a/apps/mobile/src/features/pull-requests/PullRequestControls.tsx b/apps/mobile/src/features/pull-requests/PullRequestControls.tsx
index cd9b84a2361f25b856647ac4e8e18edefdc6f9a9..5bad565b2a40f35e0bc1a4f03d010219734a359c 100644
--- a/apps/mobile/src/features/pull-requests/PullRequestControls.tsx
+++ b/apps/mobile/src/features/pull-requests/PullRequestControls.tsx
@@ -4,7 +4,7 @@ import { useNavigation } from "@react-navigation/native";
import type { PullRequestDetail } from "@t3tools/contracts";
import type { ReactNode } from "react";
import { Platform, Pressable, View } from "react-native";
-import { useSafeAreaFrame, useSafeAreaInsets } from "react-native-safe-area-context";
+import { useSafeAreaInsets } from "react-native-safe-area-context";
import { AppText as Text } from "../../components/AppText";
import { SymbolView, type AppSymbolName } from "../../components/AppSymbol";
import { MaterialButton } from "../../components/MaterialButton";
@@ -12,10 +12,7 @@ import { MaterialIconButton } from "../../components/MaterialIconButton";
import { MaterialFloatingToolbar } from "./MaterialFloatingToolbar";
import { ControlPillMenu } from "../../components/ControlPillMenu";
import { NativeHeaderToolbar } from "../../native/StackHeader";
-import {
- useNativeColumnLayoutMetrics,
- useNativeLayoutMetrics,
-} from "../../native/native-layout-metrics";
+import { useNativeLayoutMetrics } from "../../native/native-layout-metrics";
import { type PullRequestParams } from "./usePullRequestDiff";
import { usePullRequestPermissions } from "./usePullRequestPermissions";
import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider";
@@ -117,8 +114,6 @@ export function PullRequestActionToolbar(props: {
const { draft } = usePullRequestReviewDraft(props.params);
const { themeVariables: colors } = useAppearancePreferences();
const insets = useSafeAreaInsets();
- const frame = useSafeAreaFrame();
- const columnMetrics = useNativeColumnLayoutMetrics();
const nativeMetrics = useNativeLayoutMetrics();
const verticalControls = nativeMetrics !== null && nativeMetrics.verticalBarEdge !== "none";
const permissions = usePullRequestPermissions(props.params, props.pr);
@@ -140,20 +135,6 @@ export function PullRequestActionToolbar(props: {
if (!props.pr) return null;
const primaryDisabled = pendingReview ? false : agent.disabled;
const showPrimary = pendingReview || canOpenThread;
- // Match the native phone tab controls; the side rail keeps intrinsic sizing.
- const controlSize = verticalControls ? undefined : 60;
- // Reserve the native outer margins, custom-button padding, and item gaps.
- // UIKit needs this space to keep every action out of its overflow menu.
- // Duo's side rail uses an intrinsic icon item instead.
- const sideControls = Number(showAgentControls) + 1;
- const primaryWidth = verticalControls
- ? undefined
- : Math.max(
- 0,
- (columnMetrics?.width ?? frame.width - insets.left - insets.right) -
- 58 -
- sideControls * (60 + 10 + 16),
- );
if (Platform.OS === "android") {
const primary = (
);
+ if (verticalControls)
+ return (
+
+ {filesControl}
+ {agentControl}
+ {primaryControl}
+
+ );
return (
- {verticalControls ? filesControl : agentControl}
- {verticalControls ? agentControl : primaryControl}
- {verticalControls ? primaryControl : filesControl}
+ {agentControl}
+
+ {primaryControl}
+
+ {filesControl}
);
}
diff --git a/apps/mobile/src/native/NativeHeaderToolbar.tsx b/apps/mobile/src/native/NativeHeaderToolbar.tsx
index b05c498903a4196b0122d1fe522a7b53e82d2455..609e6e090edebc5a9297dda777c9fc3af81d945e 100644
--- a/apps/mobile/src/native/NativeHeaderToolbar.tsx
+++ b/apps/mobile/src/native/NativeHeaderToolbar.tsx
@@ -41,9 +41,7 @@ type NativeStackHeaderAxisBehavior = Extract<
NativeStackHeaderItem,
{ type: "button" }
>["axisBehavior"];
-type NativeToolbarItem =
- | (NativeStackHeaderItem & { readonly height?: number })
- | HeaderBarButtonSearchBarPlacementItem;
+type NativeToolbarItem = NativeStackHeaderItem | HeaderBarButtonSearchBarPlacementItem;
type NativeStackOptionsWithToolbar = NativeStackNavigationOptions & {
unstable_headerToolbarItems?: () => NativeToolbarItem[];
};
@@ -162,8 +160,6 @@ function convertToolbarChild(child: ReactNode): NativeToolbarItem | null {
: () => undefined,
sharesBackground: !child.props.separateBackground,
tintColor: child.props.tintColor as ColorValue | undefined,
- width: typeof child.props.width === "number" ? child.props.width : undefined,
- height: typeof child.props.height === "number" ? child.props.height : undefined,
variant:
child.props.variant === "done" || child.props.variant === "prominent"
? child.props.variant
@@ -189,8 +185,6 @@ function convertToolbarChild(child: ReactNode): NativeToolbarItem | null {
},
sharesBackground: !child.props.separateBackground,
tintColor: child.props.tintColor as ColorValue | undefined,
- width: typeof child.props.width === "number" ? child.props.width : undefined,
- height: typeof child.props.height === "number" ? child.props.height : undefined,
variant:
child.props.variant === "done" || child.props.variant === "prominent"
? child.props.variant
@@ -289,8 +283,6 @@ function NativeHeaderToolbarButton(_props: {
readonly tintColor?: ColorValue;
readonly variant?: "plain" | "done" | "prominent";
readonly identifier?: string;
- readonly width?: number;
- readonly height?: number;
}) {
return null;
}
@@ -308,8 +300,6 @@ function NativeHeaderToolbarMenu(_props: {
readonly tintColor?: ColorValue;
readonly title?: string;
readonly variant?: "plain" | "done" | "prominent";
- readonly width?: number;
- readonly height?: number;
}) {
return null;
}
diff --git a/apps/mobile/src/native/V5StackHeader.ios.tsx b/apps/mobile/src/native/V5StackHeader.ios.tsx
index 5dfa4e90d811624b467314287ee5b2cfd577e6fd..00f674faf30024a15a5607a1f956b533dbc4565e 100644
--- a/apps/mobile/src/native/V5StackHeader.ios.tsx
+++ b/apps/mobile/src/native/V5StackHeader.ios.tsx
@@ -21,7 +21,7 @@ import {
type HeaderItem = NonNullable["leadingItems"]>[number];
type ToolbarItem =
- | (NativeStackHeaderItem & { readonly height?: number })
+ | NativeStackHeaderItem
| HeaderBarButtonMailSearchToolbarItem
| HeaderBarButtonSearchBarPlacementItem;
type Options = NativeStackNavigationOptions & {
@@ -91,10 +91,7 @@ function convertMenu(menu: MenuInput, id: string): StackHeaderMenuIOS {
return { id, type: "menu", title: menu.title, children };
}
-function convertItems(
- items: (NativeStackHeaderItem & { readonly height?: number })[],
- prefix: string,
-): HeaderItem[] {
+function convertItems(items: NativeStackHeaderItem[], prefix: string): HeaderItem[] {
return items.map((item, index): HeaderItem => {
const id =
item.type === "spacing" ? `${prefix}:${index}` : (item.identifier ?? `${prefix}:${index}`);
@@ -121,8 +118,6 @@ function convertItems(
menu: item.disabled ? undefined : convertMenu(item.menu, `${id}:menu`),
variant: item.variant,
tintColor: item.tintColor,
- width: item.width,
- height: item.height,
hidesSharedBackground: item.hidesSharedBackground,
};
case "button":
@@ -136,8 +131,6 @@ function convertItems(
onPress: item.disabled ? undefined : item.onPress,
variant: item.variant,
tintColor: item.tintColor,
- width: item.width,
- height: item.height,
hidesSharedBackground: item.hidesSharedBackground,
};
}
diff --git a/docs/operations/mobile-screens-fork.md b/docs/operations/mobile-screens-fork.md
index 712edaeb11a11c59eb003e91e46c835a0e39d5ea..f9da54a93ab01a7c176fd15eb655015e986e5e9d 100644
--- a/docs/operations/mobile-screens-fork.md
+++ b/docs/operations/mobile-screens-fork.md
@@ -1,7 +1,7 @@
# Building the mobile Screens dependency
The mobile v5 stack uses a committed tarball from the
-[T3 Screens fork](https://github.com/pingdotgg/react-native-screens/tree/t3-v5.0.0-t3.26).
+[T3 Screens fork](https://github.com/pingdotgg/react-native-screens/tree/t3-v5.0.0-t3.27).
The fork owns the integration changes; the app does not patch this package.
Each archive includes compiled JavaScript, declarations, native source and
`t3-fork.json` recording its version, source commit and upstream base.
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a944d1fc91e8de7094a358d006e66584879b80ae..70ef13e0c7d89746ecfd5e7df33b4187ebdfdd10 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -348,7 +348,7 @@ importers:
version: 7.3.4(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
'@react-navigation/native-stack':
specifier: 7.17.6
- version: 7.17.6(patch_hash=d2d52f3776e30765519748fd5e177592dc3b9cc778c52fb00e02674dfa9042c5)(02486f76aa3d9c7d88119682fcbddcde)
+ version: 7.17.6(patch_hash=d2d52f3776e30765519748fd5e177592dc3b9cc778c52fb00e02674dfa9042c5)(6b53c4f789a319cd2c00cd296dcea732)
'@shikijs/core':
specifier: 4.2.0
version: 4.2.0
@@ -548,8 +548,8 @@ importers:
specifier: ~5.9.1
version: 5.9.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
react-native-screens:
- specifier: file:deps/react-native-screens-5.0.0-t3.26.tgz
- version: file:apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
+ specifier: file:deps/react-native-screens-5.0.0-t3.27.tgz
+ version: file:apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
react-native-shiki-engine:
specifier: ^0.3.12
version: 0.3.12(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
@@ -10891,9 +10891,9 @@ packages:
react: '*'
react-native: '*'
- react-native-screens@file:apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz:
- resolution: {integrity: sha512-OD1yeZu1HKuvBaroReihFROaofzuF2w4ORtPJXJrpAGk8AgQNusy3KaRRpeiCwIzH2KQU52SnWxrtKaYMzzQ+A==, tarball: file:apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz}
- version: 5.0.0-t3.26
+ react-native-screens@file:apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz:
+ resolution: {integrity: sha512-krNMVmduM2fXeJYveadSz6NkYI/AFN3hAAirjk42Z9wkBrPtuhmcp3E2+Me95Xdj5LBL3G3dgltUjo5vYeEtLw==, tarball: file:apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz}
+ version: 5.0.0-t3.27
peerDependencies:
react: '*'
react-native: '*'
@@ -16096,7 +16096,7 @@ snapshots:
optionalDependencies:
'@react-native-masked-view/masked-view': 0.3.2(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
- '@react-navigation/native-stack@7.17.6(patch_hash=d2d52f3776e30765519748fd5e177592dc3b9cc778c52fb00e02674dfa9042c5)(02486f76aa3d9c7d88119682fcbddcde)':
+ '@react-navigation/native-stack@7.17.6(patch_hash=d2d52f3776e30765519748fd5e177592dc3b9cc778c52fb00e02674dfa9042c5)(6b53c4f789a319cd2c00cd296dcea732)':
dependencies:
'@react-navigation/elements': 2.9.26(83de68753219ecf7f3321e065bd378be)
'@react-navigation/native': 7.3.4(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
@@ -16104,7 +16104,7 @@ snapshots:
react: 19.3.0
react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)
react-native-safe-area-context: 5.9.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
- react-native-screens: file:apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
+ react-native-screens: file:apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)
sf-symbols-typescript: 2.2.0
warn-once: 0.1.1
transitivePeerDependencies:
@@ -22097,7 +22097,7 @@ snapshots:
react: 19.3.0
react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)
- react-native-screens@file:apps/mobile/deps/react-native-screens-5.0.0-t3.26.tgz(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0):
+ react-native-screens@file:apps/mobile/deps/react-native-screens-5.0.0-t3.27.tgz(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0):
dependencies:
react: 19.3.0
react-freeze: 1.0.4(react@19.3.0)