Fix composer safe-area ownership
This commit is contained in:
@@ -14,7 +14,6 @@ import {
|
||||
Paperclip,
|
||||
} from "lucide-react-native";
|
||||
import Animated from "react-native-reanimated";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { FOOTER_HEIGHT, MAX_CONTENT_WIDTH } from "@/constants/layout";
|
||||
import { generateMessageId, type StreamItem } from "@/types/stream";
|
||||
@@ -169,7 +168,6 @@ export function Composer({
|
||||
markScrollInvestigationRender(`Composer:${serverId}:${agentId}`);
|
||||
const { theme } = useUnistyles();
|
||||
const buttonIconSize = isWeb ? theme.iconSize.md : theme.iconSize.lg;
|
||||
const insets = useSafeAreaInsets();
|
||||
const client = useHostRuntimeClient(serverId);
|
||||
const isConnected = useHostRuntimeIsConnected(serverId);
|
||||
const agentDirectoryStatus = useHostRuntimeAgentDirectoryStatus(serverId);
|
||||
@@ -882,9 +880,7 @@ export function Composer({
|
||||
);
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[styles.container, { paddingBottom: insets.bottom }, keyboardAnimatedStyle]}
|
||||
>
|
||||
<Animated.View style={[styles.container, keyboardAnimatedStyle]}>
|
||||
<AttachmentLightbox metadata={lightboxMetadata} onClose={() => setLightboxMetadata(null)} />
|
||||
{/* Input area */}
|
||||
<View style={[styles.inputAreaContainer, isComposerLocked && styles.inputAreaLocked]}>
|
||||
|
||||
@@ -108,6 +108,10 @@ vi.mock("react-native-unistyles", () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("react-native-safe-area-context", () => ({
|
||||
useSafeAreaInsets: () => ({ top: 0, right: 0, bottom: 0, left: 0 }),
|
||||
}));
|
||||
|
||||
function createPanelTestStyles(factory: PanelTestStyleFactory | PanelTestStyles): PanelTestStyles {
|
||||
return typeof factory === "function" ? factory(theme) : factory;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { ActivityIndicator, Text, View } from "react-native";
|
||||
import ReanimatedAnimated from "react-native-reanimated";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { shallow, useShallow } from "zustand/shallow";
|
||||
import { useStoreWithEqualityFn } from "zustand/traditional";
|
||||
import invariant from "tiny-invariant";
|
||||
@@ -1165,6 +1166,7 @@ function ActiveAgentComposer({
|
||||
onComposerHeightChange: (height: number) => void;
|
||||
onMessageSent: () => void;
|
||||
}) {
|
||||
const insets = useSafeAreaInsets();
|
||||
const agentInputDraft = useAgentInputDraft({
|
||||
draftKey: buildDraftStoreKey({
|
||||
serverId,
|
||||
@@ -1174,24 +1176,26 @@ function ActiveAgentComposer({
|
||||
});
|
||||
|
||||
return (
|
||||
<Composer
|
||||
agentId={agentId}
|
||||
serverId={serverId}
|
||||
isPaneFocused={isPaneFocused}
|
||||
value={agentInputDraft.text}
|
||||
onChangeText={agentInputDraft.setText}
|
||||
attachments={agentInputDraft.attachments}
|
||||
onChangeAttachments={agentInputDraft.setAttachments}
|
||||
cwd={agentInputDraft.cwd}
|
||||
clearDraft={agentInputDraft.clear}
|
||||
autoFocus={isPaneFocused}
|
||||
isSubmitLoading={isSubmitLoading}
|
||||
onAttentionInputFocus={onAttentionInputFocus}
|
||||
onAttentionPromptSend={onAttentionPromptSend}
|
||||
onAddImages={onAddImages}
|
||||
onComposerHeightChange={onComposerHeightChange}
|
||||
onMessageSent={onMessageSent}
|
||||
/>
|
||||
<View style={[styles.inputAreaWrapper, { paddingBottom: insets.bottom }]}>
|
||||
<Composer
|
||||
agentId={agentId}
|
||||
serverId={serverId}
|
||||
isPaneFocused={isPaneFocused}
|
||||
value={agentInputDraft.text}
|
||||
onChangeText={agentInputDraft.setText}
|
||||
attachments={agentInputDraft.attachments}
|
||||
onChangeAttachments={agentInputDraft.setAttachments}
|
||||
cwd={agentInputDraft.cwd}
|
||||
clearDraft={agentInputDraft.clear}
|
||||
autoFocus={isPaneFocused}
|
||||
isSubmitLoading={isSubmitLoading}
|
||||
onAttentionInputFocus={onAttentionInputFocus}
|
||||
onAttentionPromptSend={onAttentionPromptSend}
|
||||
onAddImages={onAddImages}
|
||||
onComposerHeightChange={onComposerHeightChange}
|
||||
onMessageSent={onMessageSent}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1271,6 +1275,10 @@ const styles = StyleSheet.create((theme) => ({
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
inputAreaWrapper: {
|
||||
width: "100%",
|
||||
backgroundColor: theme.colors.surface0,
|
||||
},
|
||||
historySyncOverlay: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
|
||||
@@ -1221,7 +1221,7 @@ function DraftAgentScreenContent({
|
||||
</ScrollView>
|
||||
)}
|
||||
</Animated.View>
|
||||
<View style={styles.inputAreaWrapper}>
|
||||
<View style={[styles.inputAreaWrapper, { paddingBottom: insets.bottom }]}>
|
||||
<Composer
|
||||
agentId={draftAgentIdRef.current}
|
||||
serverId={selectedServerId ?? ""}
|
||||
|
||||
@@ -145,6 +145,10 @@ vi.mock("@/constants/layout", () => ({
|
||||
useIsCompactFormFactor: () => false,
|
||||
}));
|
||||
|
||||
vi.mock("react-native-safe-area-context", () => ({
|
||||
useSafeAreaInsets: () => ({ top: 0, right: 0, bottom: 0, left: 0 }),
|
||||
}));
|
||||
|
||||
vi.mock("lucide-react-native", () => {
|
||||
const createIcon = (name: string) => (props: Record<string, unknown>) =>
|
||||
React.createElement("span", { ...props, "data-icon": name });
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Pressable, Text, View } from "react-native";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { createNameId } from "mnemonic-id";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ChevronDown, GitBranch, GitPullRequest } from "lucide-react-native";
|
||||
@@ -12,12 +13,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
|
||||
import { TitlebarDragRegion } from "@/components/desktop/titlebar-drag-region";
|
||||
import { SidebarMenuToggle } from "@/components/headers/menu-header";
|
||||
import { ScreenHeader } from "@/components/headers/screen-header";
|
||||
import {
|
||||
HEADER_INNER_HEIGHT,
|
||||
HEADER_INNER_HEIGHT_MOBILE,
|
||||
HEADER_TOP_PADDING_MOBILE,
|
||||
MAX_CONTENT_WIDTH,
|
||||
} from "@/constants/layout";
|
||||
import { HEADER_INNER_HEIGHT, MAX_CONTENT_WIDTH, useIsCompactFormFactor } from "@/constants/layout";
|
||||
import { useToast } from "@/contexts/toast-context";
|
||||
import { useAgentInputDraft } from "@/hooks/use-agent-input-draft";
|
||||
import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
|
||||
@@ -107,6 +103,8 @@ export function NewWorkspaceScreen({
|
||||
displayName: displayNameProp,
|
||||
}: NewWorkspaceScreenProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const insets = useSafeAreaInsets();
|
||||
const isCompact = useIsCompactFormFactor();
|
||||
const toast = useToast();
|
||||
const mergeWorkspaces = useSessionStore((state) => state.mergeWorkspaces);
|
||||
const setAgents = useSessionStore((state) => state.setAgents);
|
||||
@@ -453,7 +451,13 @@ export function NewWorkspaceScreen({
|
||||
leftStyle={styles.headerLeft}
|
||||
borderless
|
||||
/>
|
||||
<View style={styles.content}>
|
||||
<View
|
||||
style={[
|
||||
styles.content,
|
||||
isCompact ? styles.contentCompact : styles.contentCentered,
|
||||
isCompact ? { paddingBottom: insets.bottom } : null,
|
||||
]}
|
||||
>
|
||||
<TitlebarDragRegion />
|
||||
<View style={styles.centered}>
|
||||
<Composer
|
||||
@@ -567,12 +571,14 @@ const styles = StyleSheet.create((theme) => ({
|
||||
content: {
|
||||
position: "relative",
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingBottom: {
|
||||
xs: HEADER_INNER_HEIGHT_MOBILE + HEADER_TOP_PADDING_MOBILE + theme.spacing[6],
|
||||
md: HEADER_INNER_HEIGHT + theme.spacing[6],
|
||||
},
|
||||
},
|
||||
contentCentered: {
|
||||
justifyContent: "center",
|
||||
paddingBottom: HEADER_INNER_HEIGHT + theme.spacing[6],
|
||||
},
|
||||
contentCompact: {
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
centered: {
|
||||
width: "100%",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useMemo, useRef } from "react";
|
||||
import { Keyboard, ScrollView, Text, View } from "react-native";
|
||||
import { StyleSheet } from "react-native-unistyles";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import invariant from "tiny-invariant";
|
||||
import { Composer } from "@/components/composer";
|
||||
import { FileDropZone } from "@/components/file-drop-zone";
|
||||
@@ -48,6 +49,7 @@ export function WorkspaceDraftAgentTab({
|
||||
onCreated,
|
||||
onOpenWorkspaceFile,
|
||||
}: WorkspaceDraftAgentTabProps) {
|
||||
const insets = useSafeAreaInsets();
|
||||
const client = useHostRuntimeClient(serverId);
|
||||
const isConnected = useHostRuntimeIsConnected(serverId);
|
||||
const workspaceAuthority = useWorkspaceExecutionAuthority(serverId, workspaceId);
|
||||
@@ -282,7 +284,7 @@ export function WorkspaceDraftAgentTab({
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={styles.inputAreaWrapper}>
|
||||
<View style={[styles.inputAreaWrapper, { paddingBottom: insets.bottom }]}>
|
||||
<Composer
|
||||
agentId={tabId}
|
||||
serverId={serverId}
|
||||
|
||||
Reference in New Issue
Block a user