@@ -6,7 +6,7 @@ import { useStoreWithEqualityFn } from "zustand/traditional";
|
|||||||
import { Brain, ChevronDown, ShieldAlert, ShieldCheck, ShieldOff } from "lucide-react-native";
|
import { Brain, ChevronDown, ShieldAlert, ShieldCheck, ShieldOff } from "lucide-react-native";
|
||||||
import { getProviderIcon } from "@/components/provider-icons";
|
import { getProviderIcon } from "@/components/provider-icons";
|
||||||
import { CombinedModelSelector } from "@/components/combined-model-selector";
|
import { CombinedModelSelector } from "@/components/combined-model-selector";
|
||||||
import { useQueries, useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
import {
|
import {
|
||||||
buildFavoriteModelKey,
|
buildFavoriteModelKey,
|
||||||
@@ -481,41 +481,6 @@ function ControlledStatusBar({
|
|||||||
stackBehavior="replace"
|
stackBehavior="replace"
|
||||||
testID="agent-preferences-sheet"
|
testID="agent-preferences-sheet"
|
||||||
>
|
>
|
||||||
{providerOptions && providerOptions.length > 0 ? (
|
|
||||||
<View style={styles.sheetSection}>
|
|
||||||
<DropdownMenu
|
|
||||||
open={openSelector === "provider"}
|
|
||||||
onOpenChange={handleOpenChange("provider")}
|
|
||||||
>
|
|
||||||
<DropdownMenuTrigger
|
|
||||||
disabled={disabled || !canSelectProvider}
|
|
||||||
style={({ pressed }) => [
|
|
||||||
styles.sheetSelect,
|
|
||||||
pressed && styles.sheetSelectPressed,
|
|
||||||
(disabled || !canSelectProvider) && styles.disabledSheetSelect,
|
|
||||||
]}
|
|
||||||
accessibilityRole="button"
|
|
||||||
accessibilityLabel="Select agent provider"
|
|
||||||
testID="agent-preferences-provider"
|
|
||||||
>
|
|
||||||
<Text style={styles.sheetSelectText}>{displayProvider}</Text>
|
|
||||||
<ChevronDown size={theme.iconSize.md} color={theme.colors.foregroundMuted} />
|
|
||||||
</DropdownMenuTrigger>
|
|
||||||
<DropdownMenuContent side="top" align="start">
|
|
||||||
{providerOptions.map((provider) => (
|
|
||||||
<DropdownMenuItem
|
|
||||||
key={provider.id}
|
|
||||||
selected={provider.id === selectedProviderId}
|
|
||||||
onSelect={() => onSelectProvider?.(provider.id)}
|
|
||||||
>
|
|
||||||
{provider.label}
|
|
||||||
</DropdownMenuItem>
|
|
||||||
))}
|
|
||||||
</DropdownMenuContent>
|
|
||||||
</DropdownMenu>
|
|
||||||
</View>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{canSelectModel ? (
|
{canSelectModel ? (
|
||||||
<View style={styles.sheetSection}>
|
<View style={styles.sheetSection}>
|
||||||
<CombinedModelSelector
|
<CombinedModelSelector
|
||||||
@@ -525,9 +490,10 @@ function ControlledStatusBar({
|
|||||||
selectedModel={selectedModelId ?? ""}
|
selectedModel={selectedModelId ?? ""}
|
||||||
canSelectProvider={canSelectProviderInModelMenu}
|
canSelectProvider={canSelectProviderInModelMenu}
|
||||||
onSelect={(selectedProviderId, modelId) => {
|
onSelect={(selectedProviderId, modelId) => {
|
||||||
if (selectedProviderId === provider) {
|
if (selectedProviderId !== provider) {
|
||||||
onSelectModel?.(modelId);
|
onSelectProvider?.(selectedProviderId);
|
||||||
}
|
}
|
||||||
|
onSelectModel?.(modelId);
|
||||||
}}
|
}}
|
||||||
favoriteKeys={favoriteKeys}
|
favoriteKeys={favoriteKeys}
|
||||||
onToggleFavorite={onToggleFavoriteModel}
|
onToggleFavorite={onToggleFavoriteModel}
|
||||||
@@ -676,59 +642,34 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableProvidersQuery = useQuery({
|
const agentProviderDefinitions = useMemo(() => {
|
||||||
queryKey: ["availableProviders", serverId],
|
const definition = AGENT_PROVIDER_DEFINITIONS.find((d) => d.id === agent?.provider);
|
||||||
enabled: Boolean(client),
|
return definition ? [definition] : [];
|
||||||
staleTime: 60 * 1000,
|
}, [agent?.provider]);
|
||||||
|
|
||||||
|
const agentProviderModelQuery = useQuery({
|
||||||
|
queryKey: ["providerModels", serverId, agent?.provider, agent?.cwd ?? ""],
|
||||||
|
enabled: Boolean(client && agent?.cwd && agent?.provider),
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (!client) {
|
if (!client || !agent) {
|
||||||
throw new Error("Daemon client unavailable");
|
throw new Error("Daemon client unavailable");
|
||||||
}
|
}
|
||||||
const payload = await client.listAvailableProviders();
|
const payload = await client.listProviderModels(agent.provider, { cwd: agent.cwd });
|
||||||
if (payload.error) {
|
if (payload.error) {
|
||||||
throw new Error(payload.error);
|
throw new Error(payload.error);
|
||||||
}
|
}
|
||||||
return payload.providers.filter((entry) => entry.available).map((entry) => entry.provider);
|
return payload.models ?? [];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableProviderDefinitions = useMemo(() => {
|
const agentProviderModels = useMemo(() => {
|
||||||
const availableProviders = availableProvidersQuery.data;
|
|
||||||
if (!availableProviders) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const available = new Set(availableProviders);
|
|
||||||
return AGENT_PROVIDER_DEFINITIONS.filter((definition) => available.has(definition.id));
|
|
||||||
}, [availableProvidersQuery.data]);
|
|
||||||
|
|
||||||
const allProviderModelQueries = useQueries({
|
|
||||||
queries: availableProviderDefinitions.map((definition) => ({
|
|
||||||
queryKey: ["providerModels", serverId, definition.id, agent?.cwd ?? ""],
|
|
||||||
enabled: Boolean(client && agent?.cwd),
|
|
||||||
staleTime: 5 * 60 * 1000,
|
|
||||||
queryFn: async () => {
|
|
||||||
if (!client || !agent) {
|
|
||||||
throw new Error("Daemon client unavailable");
|
|
||||||
}
|
|
||||||
const payload = await client.listProviderModels(definition.id, { cwd: agent.cwd });
|
|
||||||
if (payload.error) {
|
|
||||||
throw new Error(payload.error);
|
|
||||||
}
|
|
||||||
return payload.models ?? [];
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
const liveAllProviderModels = useMemo(() => {
|
|
||||||
const map = new Map<string, AgentModelDefinition[]>();
|
const map = new Map<string, AgentModelDefinition[]>();
|
||||||
for (let i = 0; i < availableProviderDefinitions.length; i++) {
|
if (agent?.provider && agentProviderModelQuery.data) {
|
||||||
const query = allProviderModelQueries[i];
|
map.set(agent.provider, agentProviderModelQuery.data);
|
||||||
if (query?.data) {
|
|
||||||
map.set(availableProviderDefinitions[i]!.id, query.data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}, [allProviderModelQueries, availableProviderDefinitions]);
|
}, [agent?.provider, agentProviderModelQuery.data]);
|
||||||
|
|
||||||
const models = modelsQuery.data ?? null;
|
const models = modelsQuery.data ?? null;
|
||||||
|
|
||||||
@@ -777,9 +718,8 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
|||||||
modeOptions.length > 0 ? modeOptions : [{ id: agent.currentModeId ?? "", label: displayMode }]
|
modeOptions.length > 0 ? modeOptions : [{ id: agent.currentModeId ?? "", label: displayMode }]
|
||||||
}
|
}
|
||||||
selectedModeId={agent.currentModeId ?? undefined}
|
selectedModeId={agent.currentModeId ?? undefined}
|
||||||
providerDefinitions={availableProviderDefinitions}
|
providerDefinitions={agentProviderDefinitions}
|
||||||
allProviderModels={liveAllProviderModels}
|
allProviderModels={agentProviderModels}
|
||||||
canSelectModelProvider={(providerId) => providerId === agent.provider}
|
|
||||||
onSelectMode={(modeId) => {
|
onSelectMode={(modeId) => {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return;
|
return;
|
||||||
@@ -924,29 +864,23 @@ export function DraftAgentStatusBar({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const providerOptions = providerDefinitions.map((definition) => ({
|
const modelOptions: StatusOption[] = models.map((model) => ({
|
||||||
id: definition.id,
|
id: model.id,
|
||||||
label: definition.label,
|
label: model.label,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const modelOptions: StatusOption[] = [];
|
|
||||||
for (const model of models) {
|
|
||||||
modelOptions.push({ id: model.id, label: model.label });
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ControlledStatusBar
|
<ControlledStatusBar
|
||||||
provider={selectedProvider}
|
provider={selectedProvider}
|
||||||
providerOptions={providerOptions}
|
providerDefinitions={providerDefinitions}
|
||||||
selectedProviderId={selectedProvider}
|
allProviderModels={allProviderModels}
|
||||||
onSelectProvider={(providerId) => onSelectProvider(providerId as AgentProvider)}
|
|
||||||
modeOptions={mappedModeOptions}
|
modeOptions={mappedModeOptions}
|
||||||
selectedModeId={effectiveSelectedMode}
|
selectedModeId={effectiveSelectedMode}
|
||||||
onSelectMode={onSelectMode}
|
onSelectMode={onSelectMode}
|
||||||
modelOptions={modelOptions}
|
modelOptions={modelOptions}
|
||||||
selectedModelId={selectedModel}
|
selectedModelId={selectedModel}
|
||||||
onSelectModel={onSelectModel}
|
onSelectModel={(modelId) => onSelectModel(modelId)}
|
||||||
isModelLoading={isModelLoading}
|
isModelLoading={isAllModelsLoading}
|
||||||
favoriteKeys={favoriteKeys}
|
favoriteKeys={favoriteKeys}
|
||||||
onToggleFavoriteModel={(provider, modelId) => {
|
onToggleFavoriteModel={(provider, modelId) => {
|
||||||
void updatePreferences(toggleFavoriteModel({ preferences, provider, modelId })).catch((error) => {
|
void updatePreferences(toggleFavoriteModel({ preferences, provider, modelId })).catch((error) => {
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import { useCallback, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { View, Text, Pressable, Platform, type GestureResponderEvent } from "react-native";
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
Pressable,
|
||||||
|
Platform,
|
||||||
|
ActivityIndicator,
|
||||||
|
type GestureResponderEvent,
|
||||||
|
} from "react-native";
|
||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import {
|
import {
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
@@ -11,6 +18,7 @@ import {
|
|||||||
import type { AgentModelDefinition, AgentProvider } from "@server/server/agent/agent-sdk-types";
|
import type { AgentModelDefinition, AgentProvider } from "@server/server/agent/agent-sdk-types";
|
||||||
import type { AgentProviderDefinition } from "@server/server/agent/provider-manifest";
|
import type { AgentProviderDefinition } from "@server/server/agent/provider-manifest";
|
||||||
import { Combobox, ComboboxItem, SearchInput } from "@/components/ui/combobox";
|
import { Combobox, ComboboxItem, SearchInput } from "@/components/ui/combobox";
|
||||||
|
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
||||||
import { getProviderIcon } from "@/components/provider-icons";
|
import { getProviderIcon } from "@/components/provider-icons";
|
||||||
import type { FavoriteModelRow } from "@/hooks/use-form-preferences";
|
import type { FavoriteModelRow } from "@/hooks/use-form-preferences";
|
||||||
import {
|
import {
|
||||||
@@ -130,6 +138,7 @@ function ModelRow({
|
|||||||
}) {
|
}) {
|
||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
const ProviderIcon = getProviderIcon(row.provider);
|
const ProviderIcon = getProviderIcon(row.provider);
|
||||||
|
const isWeb = Platform.OS === "web";
|
||||||
|
|
||||||
const handleToggleFavorite = useCallback(
|
const handleToggleFavorite = useCallback(
|
||||||
(event: GestureResponderEvent) => {
|
(event: GestureResponderEvent) => {
|
||||||
@@ -139,16 +148,9 @@ function ModelRow({
|
|||||||
[onToggleFavorite, row.modelId, row.provider],
|
[onToggleFavorite, row.modelId, row.provider],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
const item = (
|
||||||
<ComboboxItem
|
<ComboboxItem
|
||||||
label={row.modelLabel}
|
label={row.modelLabel}
|
||||||
description={
|
|
||||||
disabled
|
|
||||||
? `${row.providerLabel} · Available when creating a ${row.providerLabel} agent`
|
|
||||||
: row.description
|
|
||||||
? `${row.providerLabel} · ${row.description}`
|
|
||||||
: row.providerLabel
|
|
||||||
}
|
|
||||||
selected={isSelected}
|
selected={isSelected}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
@@ -167,16 +169,39 @@ function ModelRow({
|
|||||||
accessibilityLabel={isFavorite ? "Unfavorite model" : "Favorite model"}
|
accessibilityLabel={isFavorite ? "Unfavorite model" : "Favorite model"}
|
||||||
testID={`favorite-model-${row.provider}-${row.modelId}`}
|
testID={`favorite-model-${row.provider}-${row.modelId}`}
|
||||||
>
|
>
|
||||||
<Star
|
{({ hovered }) => (
|
||||||
size={16}
|
<Star
|
||||||
color={isFavorite ? theme.colors.palette.amber[500] : theme.colors.foregroundMuted}
|
size={16}
|
||||||
fill={isFavorite ? theme.colors.palette.amber[500] : "transparent"}
|
color={
|
||||||
/>
|
isFavorite
|
||||||
|
? theme.colors.palette.amber[500]
|
||||||
|
: hovered
|
||||||
|
? theme.colors.foregroundMuted
|
||||||
|
: theme.colors.border
|
||||||
|
}
|
||||||
|
fill={isFavorite ? theme.colors.palette.amber[500] : "transparent"}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!isWeb || !row.description) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
|
||||||
|
<TooltipTrigger asChild triggerRefProp="ref">
|
||||||
|
<View>{item}</View>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="right" align="center" offset={4}>
|
||||||
|
<Text style={styles.tooltipText}>{row.description}</Text>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function FavoritesSection({
|
function FavoritesSection({
|
||||||
@@ -205,7 +230,6 @@ function FavoritesSection({
|
|||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<View style={styles.sectionHeading}>
|
<View style={styles.sectionHeading}>
|
||||||
<Star size={14} color={theme.colors.palette.amber[500]} fill={theme.colors.palette.amber[500]} />
|
|
||||||
<Text style={styles.sectionHeadingText}>Favorites</Text>
|
<Text style={styles.sectionHeadingText}>Favorites</Text>
|
||||||
</View>
|
</View>
|
||||||
{favoriteRows.map((row) => (
|
{favoriteRows.map((row) => (
|
||||||
@@ -260,7 +284,6 @@ function GroupedProviderRows({
|
|||||||
{isInline ? (
|
{isInline ? (
|
||||||
<>
|
<>
|
||||||
<View style={styles.sectionHeading}>
|
<View style={styles.sectionHeading}>
|
||||||
<ProvIcon size={14} color={theme.colors.foregroundMuted} />
|
|
||||||
<Text style={styles.sectionHeadingText}>
|
<Text style={styles.sectionHeadingText}>
|
||||||
{providerDefinition?.label ?? group.providerLabel}
|
{providerDefinition?.label ?? group.providerLabel}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -435,8 +458,10 @@ export function CombinedModelSelector({
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
}: CombinedModelSelectorProps) {
|
}: CombinedModelSelectorProps) {
|
||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
|
const isWeb = Platform.OS === "web";
|
||||||
const anchorRef = useRef<View>(null);
|
const anchorRef = useRef<View>(null);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [isContentReady, setIsContentReady] = useState(isWeb);
|
||||||
const [view, setView] = useState<SelectorView>({ kind: "all" });
|
const [view, setView] = useState<SelectorView>({ kind: "all" });
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
|
||||||
@@ -484,6 +509,23 @@ export function CombinedModelSelector({
|
|||||||
return buildSelectedTriggerLabel(selectedProviderLabel, selectedModelLabel);
|
return buildSelectedTriggerLabel(selectedProviderLabel, selectedModelLabel);
|
||||||
}, [selectedModelLabel, selectedProviderLabel]);
|
}, [selectedModelLabel, selectedProviderLabel]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isWeb) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOpen) {
|
||||||
|
setIsContentReady(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const frame = requestAnimationFrame(() => {
|
||||||
|
setIsContentReady(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => cancelAnimationFrame(frame);
|
||||||
|
}, [isOpen, isWeb]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Pressable
|
<Pressable
|
||||||
@@ -523,33 +565,41 @@ export function CombinedModelSelector({
|
|||||||
onSelect={() => {}}
|
onSelect={() => {}}
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
onOpenChange={handleOpenChange}
|
onOpenChange={handleOpenChange}
|
||||||
|
stackBehavior="push"
|
||||||
anchorRef={anchorRef}
|
anchorRef={anchorRef}
|
||||||
desktopPlacement="top-start"
|
desktopPlacement="top-start"
|
||||||
title="Select model"
|
title="Select model"
|
||||||
>
|
>
|
||||||
<SelectorContent
|
{isContentReady ? (
|
||||||
view={view}
|
<SelectorContent
|
||||||
providerDefinitions={providerDefinitions}
|
view={view}
|
||||||
allProviderModels={allProviderModels}
|
providerDefinitions={providerDefinitions}
|
||||||
selectedProvider={selectedProvider}
|
allProviderModels={allProviderModels}
|
||||||
selectedModel={selectedModel}
|
selectedProvider={selectedProvider}
|
||||||
searchQuery={searchQuery}
|
selectedModel={selectedModel}
|
||||||
onSearchChange={setSearchQuery}
|
searchQuery={searchQuery}
|
||||||
favoriteKeys={favoriteKeys}
|
onSearchChange={setSearchQuery}
|
||||||
onSelect={handleSelect}
|
favoriteKeys={favoriteKeys}
|
||||||
canSelectProvider={canSelectProvider}
|
onSelect={handleSelect}
|
||||||
onToggleFavorite={onToggleFavorite}
|
canSelectProvider={canSelectProvider}
|
||||||
onDrillDown={(providerId, providerLabel) => {
|
onToggleFavorite={onToggleFavorite}
|
||||||
setView({ kind: "provider", providerId, providerLabel });
|
onDrillDown={(providerId, providerLabel) => {
|
||||||
}}
|
setView({ kind: "provider", providerId, providerLabel });
|
||||||
onBack={
|
}}
|
||||||
view.kind === "provider"
|
onBack={
|
||||||
? () => {
|
view.kind === "provider"
|
||||||
setView({ kind: "all" });
|
? () => {
|
||||||
}
|
setView({ kind: "all" });
|
||||||
: undefined
|
}
|
||||||
}
|
: undefined
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<View style={styles.sheetLoadingState}>
|
||||||
|
<ActivityIndicator size="small" color={theme.colors.foregroundMuted} />
|
||||||
|
<Text style={styles.sheetLoadingText}>Loading model selector…</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</Combobox>
|
</Combobox>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -670,4 +720,18 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
favoriteButtonPressed: {
|
favoriteButtonPressed: {
|
||||||
backgroundColor: theme.colors.surface1,
|
backgroundColor: theme.colors.surface1,
|
||||||
},
|
},
|
||||||
|
tooltipText: {
|
||||||
|
color: theme.colors.foreground,
|
||||||
|
fontSize: theme.fontSize.xs,
|
||||||
|
},
|
||||||
|
sheetLoadingState: {
|
||||||
|
minHeight: 160,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: theme.spacing[2],
|
||||||
|
},
|
||||||
|
sheetLoadingText: {
|
||||||
|
color: theme.colors.foregroundMuted,
|
||||||
|
fontSize: theme.fontSize.sm,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export function resolveProviderLabel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildSelectedTriggerLabel(providerLabel: string, modelLabel: string): string {
|
export function buildSelectedTriggerLabel(providerLabel: string, modelLabel: string): string {
|
||||||
return `${providerLabel}: ${modelLabel}`;
|
return modelLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildModelRows(
|
export function buildModelRows(
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export interface ComboboxProps {
|
|||||||
open?: boolean;
|
open?: boolean;
|
||||||
onOpenChange?: (open: boolean) => void;
|
onOpenChange?: (open: boolean) => void;
|
||||||
enableDismissOnClose?: boolean;
|
enableDismissOnClose?: boolean;
|
||||||
|
stackBehavior?: "push" | "switch" | "replace";
|
||||||
desktopPlacement?: "top-start" | "bottom-start";
|
desktopPlacement?: "top-start" | "bottom-start";
|
||||||
/**
|
/**
|
||||||
* Prevents an initial frame at 0,0 by hiding desktop content until floating
|
* Prevents an initial frame at 0,0 by hiding desktop content until floating
|
||||||
@@ -205,12 +206,10 @@ export function ComboboxItem({
|
|||||||
</View>
|
</View>
|
||||||
{selected || trailingSlot ? (
|
{selected || trailingSlot ? (
|
||||||
<View style={styles.comboboxItemTrailingContainer}>
|
<View style={styles.comboboxItemTrailingContainer}>
|
||||||
|
<View style={styles.comboboxItemTrailingSlot}>
|
||||||
|
{selected ? <Check size={16} color={theme.colors.foregroundMuted} /> : null}
|
||||||
|
</View>
|
||||||
{trailingSlot}
|
{trailingSlot}
|
||||||
{selected ? (
|
|
||||||
<View style={styles.comboboxItemTrailingSlot}>
|
|
||||||
<Check size={16} color={theme.colors.foregroundMuted} />
|
|
||||||
</View>
|
|
||||||
) : null}
|
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
@@ -244,6 +243,7 @@ export function Combobox({
|
|||||||
open,
|
open,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
enableDismissOnClose,
|
enableDismissOnClose,
|
||||||
|
stackBehavior,
|
||||||
desktopPlacement = "top-start",
|
desktopPlacement = "top-start",
|
||||||
desktopPreventInitialFlash = true,
|
desktopPreventInitialFlash = true,
|
||||||
anchorRef,
|
anchorRef,
|
||||||
@@ -653,6 +653,7 @@ export function Combobox({
|
|||||||
backdropComponent={renderBackdrop}
|
backdropComponent={renderBackdrop}
|
||||||
enablePanDownToClose
|
enablePanDownToClose
|
||||||
enableDismissOnClose={enableDismissOnClose}
|
enableDismissOnClose={enableDismissOnClose}
|
||||||
|
stackBehavior={stackBehavior}
|
||||||
backgroundComponent={ComboboxSheetBackground}
|
backgroundComponent={ComboboxSheetBackground}
|
||||||
handleIndicatorStyle={styles.bottomSheetHandle}
|
handleIndicatorStyle={styles.bottomSheetHandle}
|
||||||
keyboardBehavior="extend"
|
keyboardBehavior="extend"
|
||||||
|
|||||||
Reference in New Issue
Block a user