From 0087e4c8ffda6c4d2057a3e0d8057967436240a3 Mon Sep 17 00:00:00 2001
From: Linus Rath <139418639+rathlinus@users.noreply.github.com>
Date: Thu, 15 Oct 2026 02:08:18 +0200
Subject: [PATCH] feat: open the composer as a centred panel on tablets
---
App.tsx | 10 +++++----
src/screens/ComposeScreen.tsx | 38 +++++++++++++++++++++++++++++++----
2 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/App.tsx b/App.tsx
index 3b7dc402..a05666e5 100644
--- a/App.tsx
+++ b/App.tsx
@@ -394,6 +394,7 @@ export default function App() {
// cached mail list instead of the "Restoring session" spinner; the real
// JMAP session comes up in the background.
const hasPersistedAccount = useAccountStore((state) => state.activeAccountId != null);
+ const { isSplit } = useLayout();
React.useEffect(() => {
if (!hasRestoredSession) {
@@ -824,10 +825,11 @@ export default function App() {
editorRef.current?.blur());
- const { shortHeight } = useLayout();
+ const { shortHeight, isSplit } = useLayout();
const typingInShortWindow = shortHeight && kbObstruction > 0;
// When the keyboard is up it covers the bottom safe area, so we don't
// need to add it on top — pad by whichever is larger.
- const bottomPad = Math.max(kbObstruction, insets.bottom);
+ // On a tablet the composer is a centred panel that stops PANEL_MARGIN
+ // short of the screen bottom; the keyboard covers that much less of it.
+ const bottomPad = isSplit
+ ? Math.max(0, kbObstruction - PANEL_MARGIN)
+ : Math.max(kbObstruction, insets.bottom);
const replyTo = route.params?.replyTo;
const draft = route.params?.draft;
const mode = route.params?.mode ?? 'compose';
@@ -2263,8 +2267,8 @@ export default function ComposeScreen({ route, navigation }: Props) {
);
};
- return (
-
+ const composer = (
+
);
+ if (!isSplit) return composer;
+ // Tablet: a centred panel over the dimmed screen it was opened from.
+ return (
+
+ {composer}
+
+ );
}
+/** Gap between the tablet composer panel and the screen edges. */
+const PANEL_MARGIN = 24;
+
function makeStyles(c: ThemePalette) {
return StyleSheet.create({
container: { flex: 1, backgroundColor: c.background },
flex: { flex: 1 },
+ panelBackdrop: {
+ flex: 1,
+ backgroundColor: 'rgba(0,0,0,0.5)',
+ alignItems: 'center',
+ paddingHorizontal: PANEL_MARGIN,
+ },
+ panel: {
+ flex: 1,
+ width: '100%',
+ maxWidth: 760,
+ borderRadius: radius.lg,
+ borderWidth: 1,
+ borderColor: c.border,
+ overflow: 'hidden',
+ backgroundColor: c.background,
+ },
scrollContent: { flexGrow: 1 },
header: {