Update files
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import { forwardRef, useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import {
|
||||
@@ -7,14 +7,17 @@ import {
|
||||
Pressable,
|
||||
ScrollView,
|
||||
Text,
|
||||
TextInput,
|
||||
View,
|
||||
} from "react-native";
|
||||
import type { TextInputProps } from "react-native";
|
||||
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
||||
import { getOverlayRoot, OVERLAY_Z } from "../lib/overlay-root";
|
||||
import {
|
||||
BottomSheetModal,
|
||||
BottomSheetBackdrop,
|
||||
BottomSheetScrollView,
|
||||
BottomSheetTextInput,
|
||||
type BottomSheetBackgroundProps,
|
||||
} from "@gorhom/bottom-sheet";
|
||||
import { X } from "lucide-react-native";
|
||||
@@ -244,3 +247,20 @@ export function AdaptiveModalSheet({
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TextInput that automatically uses BottomSheetTextInput on mobile
|
||||
* for proper keyboard dodging in AdaptiveModalSheet.
|
||||
*/
|
||||
export const AdaptiveTextInput = forwardRef<TextInput, TextInputProps>(
|
||||
function AdaptiveTextInput(props, ref) {
|
||||
const isMobile =
|
||||
UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
||||
|
||||
if (isMobile) {
|
||||
return <BottomSheetTextInput ref={ref as any} {...props} />;
|
||||
}
|
||||
|
||||
return <TextInput ref={ref} {...props} />;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { useCallback, useMemo, useRef, useState } from "react";
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { Alert, Text, TextInput, View } from "react-native";
|
||||
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
||||
import { BottomSheetTextInput } from "@gorhom/bottom-sheet";
|
||||
import { Link2 } from "lucide-react-native";
|
||||
import { useDaemonRegistry, type HostProfile } from "@/contexts/daemon-registry-context";
|
||||
import { normalizeHostPort } from "@/utils/daemon-endpoints";
|
||||
import { DaemonConnectionTestError, probeDaemonEndpoint } from "@/utils/test-daemon-connection";
|
||||
import { AdaptiveModalSheet } from "./adaptive-modal-sheet";
|
||||
import { AdaptiveModalSheet, AdaptiveTextInput } from "./adaptive-modal-sheet";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
@@ -134,7 +133,6 @@ export function AddHostModal({ visible, onClose, onCancel, onSaved, targetServer
|
||||
const isMobile =
|
||||
UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
||||
|
||||
const InputComponent = useMemo(() => (isMobile ? BottomSheetTextInput : TextInput), [isMobile]);
|
||||
const hostInputRef = useRef<TextInput>(null);
|
||||
|
||||
const [endpointRaw, setEndpointRaw] = useState("");
|
||||
@@ -223,8 +221,8 @@ export function AddHostModal({ visible, onClose, onCancel, onSaved, targetServer
|
||||
|
||||
<View style={styles.field}>
|
||||
<Text style={styles.label}>Host</Text>
|
||||
<InputComponent
|
||||
ref={hostInputRef as any}
|
||||
<AdaptiveTextInput
|
||||
ref={hostInputRef}
|
||||
value={endpointRaw}
|
||||
onChangeText={setEndpointRaw}
|
||||
placeholder="host:6767"
|
||||
|
||||
@@ -113,7 +113,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
<DropdownMenuItem
|
||||
key={mode.id}
|
||||
selected={isActive}
|
||||
selectedVariant="accent"
|
||||
description={mode.description}
|
||||
onSelect={() => handleModeChange(mode.id)}
|
||||
>
|
||||
@@ -155,7 +154,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
<DropdownMenuItem
|
||||
key={model.id}
|
||||
selected={isActive}
|
||||
selectedVariant="accent"
|
||||
description={model.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
@@ -202,7 +200,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
<DropdownMenuItem
|
||||
key={opt.id}
|
||||
selected={isActive}
|
||||
selectedVariant="accent"
|
||||
description={opt.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
@@ -222,7 +219,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -271,7 +267,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
<DropdownMenuItem
|
||||
key={model.id}
|
||||
selected={isActive}
|
||||
selectedVariant="accent"
|
||||
description={model.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
@@ -314,7 +309,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
<DropdownMenuItem
|
||||
key={opt.id}
|
||||
selected={isActive}
|
||||
selectedVariant="accent"
|
||||
description={opt.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ScrollView, type ScrollView as ScrollViewType } from "react-native-gest
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import * as Linking from "expo-linking";
|
||||
import { ChevronDown, ChevronRight, GitBranch, MoreVertical, ArrowLeftRight, ListChevronsDownUp, ListChevronsUpDown } from "lucide-react-native";
|
||||
import { Archive, ChevronDown, ChevronRight, GitBranch, MoreVertical, ArrowLeftRight, ListChevronsDownUp, ListChevronsUpDown } from "lucide-react-native";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useSessionStore } from "@/stores/session-store";
|
||||
import {
|
||||
@@ -75,7 +75,7 @@ interface GitAction {
|
||||
disabled: boolean;
|
||||
status: ActionStatus;
|
||||
description?: string;
|
||||
destructive?: boolean;
|
||||
icon?: ReactElement;
|
||||
handler: () => void;
|
||||
}
|
||||
|
||||
@@ -1048,7 +1048,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
|
||||
successLabel: "Archived",
|
||||
disabled: archiveDisabled,
|
||||
status: archiveAction.status,
|
||||
destructive: true,
|
||||
icon: <Archive size={16} color={theme.colors.foregroundMuted} />,
|
||||
handler: archiveAction.trigger,
|
||||
});
|
||||
}
|
||||
@@ -1198,7 +1198,7 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
|
||||
<DropdownMenuItem
|
||||
key={action.id}
|
||||
testID={`changes-menu-${action.id}`}
|
||||
destructive={action.destructive}
|
||||
leading={action.icon}
|
||||
disabled={action.disabled}
|
||||
status={action.status}
|
||||
pendingLabel={action.pendingLabel}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Text, TextInput, View } from "react-native";
|
||||
import { BottomSheetTextInput } from "@gorhom/bottom-sheet";
|
||||
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
||||
import { AdaptiveModalSheet } from "./adaptive-modal-sheet";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { AdaptiveModalSheet, AdaptiveTextInput } from "./adaptive-modal-sheet";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
@@ -45,8 +44,6 @@ export interface NameHostModalProps {
|
||||
|
||||
export function NameHostModal({ visible, serverId, hostname, onSkip, onSave }: NameHostModalProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
||||
const InputComponent = useMemo(() => (isMobile ? BottomSheetTextInput : TextInput), [isMobile]);
|
||||
|
||||
const [label, setLabel] = useState("");
|
||||
const hasEditedRef = useRef(false);
|
||||
@@ -91,7 +88,7 @@ export function NameHostModal({ visible, serverId, hostname, onSkip, onSave }: N
|
||||
|
||||
<View style={styles.field}>
|
||||
<Text style={styles.label}>Label</Text>
|
||||
<InputComponent
|
||||
<AdaptiveTextInput
|
||||
value={label}
|
||||
onChangeText={handleChange}
|
||||
placeholder={suggested}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { Alert, Text, TextInput, View } from "react-native";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Alert, Text, View } from "react-native";
|
||||
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
|
||||
import { BottomSheetTextInput } from "@gorhom/bottom-sheet";
|
||||
import { Link } from "lucide-react-native";
|
||||
import { useDaemonRegistry, type HostProfile } from "@/contexts/daemon-registry-context";
|
||||
import { decodeOfferFragmentPayload } from "@/utils/daemon-endpoints";
|
||||
import { ConnectionOfferSchema } from "@server/shared/connection-offer";
|
||||
import { AdaptiveModalSheet } from "./adaptive-modal-sheet";
|
||||
import { AdaptiveModalSheet, AdaptiveTextInput } from "./adaptive-modal-sheet";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
@@ -55,7 +54,6 @@ export function PairLinkModal({ visible, onClose, onCancel, onSaved, targetServe
|
||||
const { daemons, upsertDaemonFromOfferUrl } = useDaemonRegistry();
|
||||
const isMobile =
|
||||
UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm";
|
||||
const InputComponent = useMemo(() => (isMobile ? BottomSheetTextInput : TextInput), [isMobile]);
|
||||
|
||||
const [offerUrl, setOfferUrl] = useState("");
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -143,7 +141,7 @@ export function PairLinkModal({ visible, onClose, onCancel, onSaved, targetServe
|
||||
|
||||
<View style={styles.field}>
|
||||
<Text style={styles.label}>Pairing link</Text>
|
||||
<InputComponent
|
||||
<AdaptiveTextInput
|
||||
testID="pair-link-input"
|
||||
nativeID="pair-link-input"
|
||||
accessibilityLabel="pair-link-input"
|
||||
|
||||
@@ -470,12 +470,11 @@ export function DropdownMenuItem({
|
||||
}
|
||||
onSelect?.();
|
||||
}}
|
||||
style={({ pressed }) => [
|
||||
style={({ pressed, hovered }) => [
|
||||
styles.item,
|
||||
selected ? (selectedVariant === "accent" ? styles.itemSelectedAccent : styles.itemSelected) : null,
|
||||
destructive && !isSuccess ? styles.itemDestructive : null,
|
||||
isDisabled ? styles.itemDisabled : null,
|
||||
pressed && !isDisabled ? styles.itemPressed : null,
|
||||
(hovered || pressed) && !isDisabled ? styles.itemHovered : null,
|
||||
]}
|
||||
>
|
||||
{showSelectedCheck ? (
|
||||
@@ -527,7 +526,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
content: {
|
||||
backgroundColor: theme.colors.surface0,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderAccent,
|
||||
borderColor: theme.colors.border,
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
overflow: "hidden",
|
||||
shadowColor: "#000",
|
||||
@@ -567,7 +566,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
paddingVertical: theme.spacing[2],
|
||||
},
|
||||
itemPressed: {
|
||||
itemHovered: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
},
|
||||
itemSelected: {
|
||||
@@ -579,13 +578,10 @@ const styles = StyleSheet.create((theme) => ({
|
||||
itemDisabled: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
itemDestructive: {
|
||||
backgroundColor: "rgba(248, 81, 73, 0.08)",
|
||||
},
|
||||
itemText: {
|
||||
fontSize: theme.fontSize.sm,
|
||||
color: theme.colors.foreground,
|
||||
fontWeight: theme.fontWeight.medium,
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
},
|
||||
itemTextDestructive: {
|
||||
color: theme.colors.destructive,
|
||||
|
||||
Reference in New Issue
Block a user