Update files
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
ActivityIndicator,
|
||||
Platform,
|
||||
} from "react-native";
|
||||
import type { StyleProp, ViewStyle, TextProps } from "react-native";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import {
|
||||
BottomSheetModal,
|
||||
@@ -16,7 +17,7 @@ import {
|
||||
BottomSheetBackgroundProps,
|
||||
} from "@gorhom/bottom-sheet";
|
||||
import Animated from "react-native-reanimated";
|
||||
import { ChevronDown, ChevronRight, Pencil, Check, X } from "lucide-react-native";
|
||||
import { ChevronDown, ChevronRight, Pencil, Check, X, Bot, Brain, Shield } from "lucide-react-native";
|
||||
import { theme as defaultTheme } from "@/styles/theme";
|
||||
import type {
|
||||
AgentMode,
|
||||
@@ -312,6 +313,8 @@ interface ComboSelectProps {
|
||||
allowCustomValue?: boolean;
|
||||
isLoading?: boolean;
|
||||
onSelect: (id: string) => void;
|
||||
icon?: ReactElement;
|
||||
showLabel?: boolean;
|
||||
}
|
||||
|
||||
export function ComboSelect({
|
||||
@@ -324,6 +327,8 @@ export function ComboSelect({
|
||||
allowCustomValue = false,
|
||||
isLoading,
|
||||
onSelect,
|
||||
icon,
|
||||
showLabel = true,
|
||||
}: ComboSelectProps): ReactElement {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const anchorRef = useRef<View>(null);
|
||||
@@ -336,7 +341,7 @@ export function ComboSelect({
|
||||
|
||||
return (
|
||||
<>
|
||||
<CompactSelectField
|
||||
<FormSelectTrigger
|
||||
label={label}
|
||||
value={displayValue}
|
||||
placeholder={placeholder}
|
||||
@@ -344,6 +349,8 @@ export function ComboSelect({
|
||||
disabled={disabled}
|
||||
isLoading={isLoading}
|
||||
controlRef={anchorRef}
|
||||
icon={icon}
|
||||
showLabel={showLabel}
|
||||
/>
|
||||
<Combobox
|
||||
options={options}
|
||||
@@ -368,9 +375,14 @@ interface CompactSelectFieldProps {
|
||||
disabled?: boolean;
|
||||
isLoading?: boolean;
|
||||
controlRef?: React.RefObject<View | null>;
|
||||
icon?: ReactElement;
|
||||
showLabel?: boolean;
|
||||
containerStyle?: StyleProp<ViewStyle>;
|
||||
valueEllipsizeMode?: TextProps["ellipsizeMode"];
|
||||
testID?: string;
|
||||
}
|
||||
|
||||
function CompactSelectField({
|
||||
export function FormSelectTrigger({
|
||||
label,
|
||||
value,
|
||||
placeholder,
|
||||
@@ -378,6 +390,11 @@ function CompactSelectField({
|
||||
disabled,
|
||||
isLoading,
|
||||
controlRef,
|
||||
icon,
|
||||
showLabel = true,
|
||||
containerStyle,
|
||||
valueEllipsizeMode,
|
||||
testID,
|
||||
}: CompactSelectFieldProps): ReactElement {
|
||||
const getWebKey = useCallback((event: unknown): string | null => {
|
||||
if (!event || typeof event !== "object") return null;
|
||||
@@ -411,25 +428,38 @@ function CompactSelectField({
|
||||
<Pressable
|
||||
ref={controlRef}
|
||||
onPress={onPress}
|
||||
testID={testID}
|
||||
// @ts-ignore - tabIndex is web-only
|
||||
tabIndex={0}
|
||||
accessibilityRole="button"
|
||||
// @ts-ignore - onKeyDown is web-only
|
||||
onKeyDown={handleKeyDown}
|
||||
disabled={disabled}
|
||||
style={[styles.compactSelectControl, disabled && styles.compactSelectControlDisabled]}
|
||||
style={[
|
||||
styles.compactSelectControl,
|
||||
!showLabel && styles.compactSelectControlInline,
|
||||
containerStyle,
|
||||
disabled && styles.compactSelectControlDisabled,
|
||||
]}
|
||||
>
|
||||
<Text style={styles.compactSelectLabel}>{label}</Text>
|
||||
{isLoading ? (
|
||||
<ActivityIndicator size="small" color={defaultTheme.colors.foregroundMuted} />
|
||||
) : (
|
||||
<Text
|
||||
style={value ? styles.compactSelectValue : styles.compactSelectPlaceholder}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{value || placeholder || "Select..."}
|
||||
</Text>
|
||||
)}
|
||||
{icon ? <View style={styles.compactSelectLeading}>{icon}</View> : null}
|
||||
<View style={styles.compactSelectValueContainer}>
|
||||
{showLabel ? (
|
||||
<Text style={styles.compactSelectLabel}>{label}</Text>
|
||||
) : null}
|
||||
{isLoading ? (
|
||||
<ActivityIndicator size="small" color={defaultTheme.colors.foregroundMuted} />
|
||||
) : (
|
||||
<Text
|
||||
style={value ? styles.compactSelectValue : styles.compactSelectPlaceholder}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode={valueEllipsizeMode}
|
||||
>
|
||||
{value || placeholder || "Select..."}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<ChevronDown size={16} color={defaultTheme.colors.foregroundMuted} />
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
@@ -466,31 +496,28 @@ export function AgentConfigRow({
|
||||
providerDefinitions.map((def) => ({
|
||||
id: def.id,
|
||||
label: def.label,
|
||||
description: def.description,
|
||||
})),
|
||||
[providerDefinitions]
|
||||
);
|
||||
|
||||
const modeSelectOptions: ComboSelectOption[] = useMemo(() => {
|
||||
if (modeOptions.length === 0) {
|
||||
return [{ id: "", label: "Default", description: "Provider default mode" }];
|
||||
return [{ id: "", label: "Default" }];
|
||||
}
|
||||
return modeOptions.map((mode) => ({
|
||||
id: mode.id,
|
||||
label: mode.label,
|
||||
description: mode.description,
|
||||
}));
|
||||
}, [modeOptions]);
|
||||
|
||||
const modelSelectOptions: ComboSelectOption[] = useMemo(() => {
|
||||
const opts: ComboSelectOption[] = [
|
||||
{ id: "", label: "Auto", description: "Provider default model" },
|
||||
{ id: "", label: "Auto" },
|
||||
];
|
||||
for (const model of models) {
|
||||
opts.push({
|
||||
id: model.id,
|
||||
label: model.label,
|
||||
description: model.description,
|
||||
});
|
||||
}
|
||||
return opts;
|
||||
@@ -502,18 +529,20 @@ export function AgentConfigRow({
|
||||
<View style={styles.agentConfigRow}>
|
||||
<View style={styles.agentConfigColumn}>
|
||||
<ComboSelect
|
||||
label="PROVIDER"
|
||||
label="Provider"
|
||||
title="Select provider"
|
||||
value={selectedProvider}
|
||||
options={providerOptions}
|
||||
placeholder="Select..."
|
||||
disabled={disabled}
|
||||
onSelect={onSelectProvider}
|
||||
icon={<Bot size={16} color={defaultTheme.colors.foregroundMuted} />}
|
||||
showLabel={false}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.agentConfigColumn}>
|
||||
<ComboSelect
|
||||
label="MODEL"
|
||||
label="Model"
|
||||
title="Select model"
|
||||
value={selectedModel}
|
||||
options={modelSelectOptions}
|
||||
@@ -521,17 +550,21 @@ export function AgentConfigRow({
|
||||
disabled={disabled}
|
||||
isLoading={isModelLoading}
|
||||
onSelect={onSelectModel}
|
||||
icon={<Brain size={16} color={defaultTheme.colors.foregroundMuted} />}
|
||||
showLabel={false}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.agentConfigColumn}>
|
||||
<ComboSelect
|
||||
label="MODE"
|
||||
label="Mode"
|
||||
title="Select mode"
|
||||
value={effectiveSelectedMode}
|
||||
options={modeSelectOptions}
|
||||
placeholder="Default"
|
||||
disabled={disabled || modeOptions.length === 0}
|
||||
onSelect={onSelectMode}
|
||||
icon={<Shield size={16} color={defaultTheme.colors.foregroundMuted} />}
|
||||
showLabel={false}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
@@ -563,7 +596,6 @@ export function AssistantDropdown({
|
||||
providerDefinitions.map((def) => ({
|
||||
id: def.id,
|
||||
label: def.label,
|
||||
description: def.description,
|
||||
})),
|
||||
[providerDefinitions]
|
||||
);
|
||||
@@ -1405,26 +1437,46 @@ const styles = StyleSheet.create((theme) => ({
|
||||
borderWidth: theme.borderWidth[1],
|
||||
borderColor: theme.colors.border,
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
paddingVertical: theme.spacing[2],
|
||||
paddingVertical: theme.spacing[1],
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
gap: theme.spacing[1],
|
||||
},
|
||||
compactSelectControlInline: {
|
||||
minHeight: 40,
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
gap: theme.spacing[1],
|
||||
},
|
||||
compactSelectControlDisabled: {
|
||||
opacity: theme.opacity[50],
|
||||
},
|
||||
compactSelectTopRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing[1],
|
||||
},
|
||||
compactSelectLeading: {
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
marginRight: theme.spacing[1],
|
||||
},
|
||||
compactSelectValueContainer: {
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
gap: theme.spacing[1],
|
||||
},
|
||||
compactSelectLabel: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.xs,
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontWeight: theme.fontWeight.medium,
|
||||
textTransform: "uppercase",
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
compactSelectValue: {
|
||||
color: theme.colors.foreground,
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontSize: theme.fontSize.base,
|
||||
},
|
||||
compactSelectPlaceholder: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontSize: theme.fontSize.base,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { AdaptiveModalSheet } from "@/components/adaptive-modal-sheet";
|
||||
@@ -67,7 +66,9 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
return models.find((m) => m.id === agent.model) ?? null;
|
||||
}, [models, agent.model]);
|
||||
|
||||
const displayModel = selectedModel?.label ?? agent.model ?? "default";
|
||||
const displayModel = selectedModel
|
||||
? selectedModel.label
|
||||
: agent.model ?? "default";
|
||||
|
||||
const thinkingOptions = selectedModel?.thinkingOptions ?? null;
|
||||
const selectedThinkingId =
|
||||
@@ -106,14 +107,12 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
maxWidth={dropdownMaxWidth}
|
||||
testID="agent-mode-menu"
|
||||
>
|
||||
<DropdownMenuLabel>Mode</DropdownMenuLabel>
|
||||
{agent.availableModes.map((mode) => {
|
||||
const isActive = mode.id === agent.currentModeId;
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={mode.id}
|
||||
selected={isActive}
|
||||
description={mode.description}
|
||||
onSelect={() => handleModeChange(mode.id)}
|
||||
>
|
||||
{mode.label}
|
||||
@@ -147,14 +146,12 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
maxWidth={dropdownMaxWidth}
|
||||
testID="agent-model-menu"
|
||||
>
|
||||
<DropdownMenuLabel>Model</DropdownMenuLabel>
|
||||
{models?.map((model) => {
|
||||
const isActive = model.id === agent.model;
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={model.id}
|
||||
selected={isActive}
|
||||
description={model.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
return;
|
||||
@@ -193,14 +190,12 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
maxWidth={dropdownMaxWidth}
|
||||
testID="agent-thinking-menu"
|
||||
>
|
||||
<DropdownMenuLabel>Thinking</DropdownMenuLabel>
|
||||
{thinkingOptions.map((opt) => {
|
||||
const isActive = opt.id === selectedThinkingId;
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={opt.id}
|
||||
selected={isActive}
|
||||
description={opt.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
return;
|
||||
@@ -245,7 +240,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
testID="agent-preferences-sheet"
|
||||
>
|
||||
<View style={styles.sheetSection}>
|
||||
<Text style={styles.sheetLabel}>Model</Text>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
style={({ pressed }) => [
|
||||
@@ -260,14 +254,12 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
<ChevronDown size={16} color={theme.colors.foregroundMuted} />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="top" align="start">
|
||||
<DropdownMenuLabel>Model</DropdownMenuLabel>
|
||||
{models?.map((model) => {
|
||||
const isActive = model.id === agent.model;
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={model.id}
|
||||
selected={isActive}
|
||||
description={model.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
return;
|
||||
@@ -287,7 +279,6 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
|
||||
{thinkingOptions && thinkingOptions.length > 1 && (
|
||||
<View style={styles.sheetSection}>
|
||||
<Text style={styles.sheetLabel}>Thinking</Text>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
style={({ pressed }) => [
|
||||
@@ -298,21 +289,19 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
|
||||
accessibilityLabel="Select thinking option"
|
||||
testID="agent-preferences-thinking"
|
||||
>
|
||||
<Text style={styles.sheetSelectText}>{displayThinking}</Text>
|
||||
<ChevronDown size={16} color={theme.colors.foregroundMuted} />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="top" align="start">
|
||||
<DropdownMenuLabel>Thinking</DropdownMenuLabel>
|
||||
{thinkingOptions.map((opt) => {
|
||||
const isActive = opt.id === selectedThinkingId;
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={opt.id}
|
||||
selected={isActive}
|
||||
description={opt.description}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
return;
|
||||
<Text style={styles.sheetSelectText}>{displayThinking}</Text>
|
||||
<ChevronDown size={16} color={theme.colors.foregroundMuted} />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="top" align="start">
|
||||
{thinkingOptions.map((opt) => {
|
||||
const isActive = opt.id === selectedThinkingId;
|
||||
return (
|
||||
<DropdownMenuItem
|
||||
key={opt.id}
|
||||
selected={isActive}
|
||||
onSelect={() => {
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
void client
|
||||
.setAgentThinkingOption(agentId, opt.id === "default" ? null : opt.id)
|
||||
@@ -361,7 +350,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
},
|
||||
modeBadgeText: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.xs,
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontWeight: theme.fontWeight.normal,
|
||||
},
|
||||
prefsButton: {
|
||||
@@ -378,11 +367,6 @@ const styles = StyleSheet.create((theme) => ({
|
||||
sheetSection: {
|
||||
gap: theme.spacing[2],
|
||||
},
|
||||
sheetLabel: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontWeight: theme.fontWeight.semibold,
|
||||
},
|
||||
sheetSelect: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
@@ -401,7 +385,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
sheetSelectText: {
|
||||
flex: 1,
|
||||
color: theme.colors.foreground,
|
||||
fontSize: theme.fontSize.sm,
|
||||
fontSize: theme.fontSize.base,
|
||||
fontWeight: theme.fontWeight.semibold,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -1050,14 +1050,24 @@ export function GitDiffPane({ serverId, agentId, cwd }: GitDiffPaneProps) {
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={gitActions.primary.label}
|
||||
>
|
||||
{gitActions.primary.status === "pending" ? (
|
||||
<ActivityIndicator size="small" color={theme.colors.foreground} style={styles.splitButtonSpinner} />
|
||||
) : (
|
||||
<View style={styles.splitButtonContent}>
|
||||
<View style={styles.splitButtonPrimaryInner}>
|
||||
<View
|
||||
style={[
|
||||
styles.splitButtonContent,
|
||||
gitActions.primary.status === "pending" && styles.splitButtonContentHidden,
|
||||
]}
|
||||
>
|
||||
{gitActions.primary.icon}
|
||||
<Text style={styles.splitButtonText}>{getActionDisplayLabel(gitActions.primary)}</Text>
|
||||
</View>
|
||||
)}
|
||||
{gitActions.primary.status === "pending" ? (
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={theme.colors.foreground}
|
||||
style={styles.splitButtonSpinnerOverlay}
|
||||
/>
|
||||
) : null}
|
||||
</View>
|
||||
</Pressable>
|
||||
{gitActions.secondary.length > 0 ? (
|
||||
<DropdownMenu>
|
||||
@@ -1292,15 +1302,21 @@ const styles = StyleSheet.create((theme) => ({
|
||||
},
|
||||
splitButtonPrimary: {
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
paddingVertical: theme.spacing[2],
|
||||
paddingVertical: theme.spacing[1],
|
||||
justifyContent: "center",
|
||||
position: "relative",
|
||||
},
|
||||
splitButtonPrimaryInner: {
|
||||
position: "relative",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
splitButtonPrimaryDisabled: {
|
||||
opacity: 0.6,
|
||||
},
|
||||
splitButtonText: {
|
||||
fontSize: theme.fontSize.xs,
|
||||
lineHeight: theme.fontSize.xs * 1.5,
|
||||
fontSize: theme.fontSize.sm,
|
||||
lineHeight: theme.fontSize.sm * 1.5,
|
||||
color: theme.colors.foreground,
|
||||
fontWeight: theme.fontWeight.medium,
|
||||
},
|
||||
@@ -1310,9 +1326,12 @@ const styles = StyleSheet.create((theme) => ({
|
||||
justifyContent: "center",
|
||||
gap: theme.spacing[2],
|
||||
},
|
||||
splitButtonSpinner: {
|
||||
height: theme.fontSize.xs * 1.5,
|
||||
width: theme.fontSize.xs * 1.5,
|
||||
splitButtonContentHidden: {
|
||||
opacity: 0,
|
||||
},
|
||||
splitButtonSpinnerOverlay: {
|
||||
position: "absolute",
|
||||
transform: [{ scale: 0.8 }],
|
||||
},
|
||||
splitButtonCaret: {
|
||||
width: 36,
|
||||
|
||||
@@ -20,13 +20,7 @@ import {
|
||||
} from "@gorhom/bottom-sheet";
|
||||
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
|
||||
import { Check, Search } from "lucide-react-native";
|
||||
import {
|
||||
flip,
|
||||
offset as floatingOffset,
|
||||
shift,
|
||||
size as floatingSize,
|
||||
useFloating,
|
||||
} from "@floating-ui/react-native";
|
||||
import { flip, offset as floatingOffset, shift, size as floatingSize, useFloating } from "@floating-ui/react-native";
|
||||
import { getNextActiveIndex } from "./combobox-keyboard";
|
||||
|
||||
const IS_WEB = Platform.OS === "web";
|
||||
@@ -132,21 +126,24 @@ export function ComboboxItem({
|
||||
<Pressable
|
||||
testID={testID}
|
||||
onPress={onPress}
|
||||
style={({ pressed }) => [
|
||||
style={({ pressed, hovered = false }) => [
|
||||
styles.comboboxItem,
|
||||
hovered && styles.comboboxItemHovered,
|
||||
pressed && styles.comboboxItemPressed,
|
||||
active && styles.comboboxItemActive,
|
||||
]}
|
||||
>
|
||||
<View style={styles.comboboxItemCheckSlot}>
|
||||
{selected ? <Check size={16} color={theme.colors.foreground} /> : null}
|
||||
</View>
|
||||
<View style={styles.comboboxItemContent}>
|
||||
<Text numberOfLines={1} style={styles.comboboxItemLabel}>{label}</Text>
|
||||
{description ? (
|
||||
<Text numberOfLines={2} style={styles.comboboxItemDescription}>{description}</Text>
|
||||
) : null}
|
||||
</View>
|
||||
{selected ? (
|
||||
<View style={styles.comboboxItemTrailingSlot}>
|
||||
<Check size={16} color={theme.colors.foregroundMuted} />
|
||||
</View>
|
||||
) : null}
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
@@ -214,8 +211,8 @@ export function Combobox({
|
||||
|
||||
const middleware = useMemo(
|
||||
() => [
|
||||
floatingOffset({ mainAxis: 4 }),
|
||||
flip({ padding: collisionPadding }),
|
||||
floatingOffset(Platform.OS === "web" ? 0 : 4),
|
||||
...(Platform.OS === "web" ? [] : [flip({ padding: collisionPadding })]),
|
||||
shift({ padding: collisionPadding }),
|
||||
floatingSize({
|
||||
padding: collisionPadding,
|
||||
@@ -238,7 +235,7 @@ export function Combobox({
|
||||
);
|
||||
|
||||
const { refs, floatingStyles, update } = useFloating({
|
||||
placement: "bottom-start",
|
||||
placement: Platform.OS === "web" ? "top-start" : "bottom-start",
|
||||
middleware,
|
||||
sameScrollView: false,
|
||||
elements: {
|
||||
@@ -551,10 +548,14 @@ const styles = StyleSheet.create((theme) => ({
|
||||
searchInputContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: theme.colors.border,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.border,
|
||||
backgroundColor: theme.colors.surface1,
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
marginBottom: theme.spacing[1],
|
||||
marginHorizontal: theme.spacing[2],
|
||||
marginBottom: theme.spacing[2],
|
||||
marginTop: theme.spacing[1],
|
||||
gap: theme.spacing[2],
|
||||
},
|
||||
searchInput: {
|
||||
@@ -571,17 +572,27 @@ const styles = StyleSheet.create((theme) => ({
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
paddingVertical: theme.spacing[2],
|
||||
borderRadius: theme.borderRadius.md,
|
||||
...(IS_WEB
|
||||
? {}
|
||||
: {
|
||||
marginHorizontal: theme.spacing[1],
|
||||
marginBottom: theme.spacing[1],
|
||||
}),
|
||||
},
|
||||
comboboxItemHovered: {
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
comboboxItemPressed: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
comboboxItemActive: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
comboboxItemCheckSlot: {
|
||||
comboboxItemTrailingSlot: {
|
||||
width: 16,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
marginLeft: "auto",
|
||||
},
|
||||
comboboxItemContent: {
|
||||
flex: 1,
|
||||
@@ -603,7 +614,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
fontSize: theme.fontSize.sm,
|
||||
},
|
||||
bottomSheetBackground: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
backgroundColor: theme.colors.surface0,
|
||||
borderTopLeftRadius: theme.borderRadius["2xl"],
|
||||
borderTopRightRadius: theme.borderRadius["2xl"],
|
||||
},
|
||||
@@ -616,13 +627,14 @@ const styles = StyleSheet.create((theme) => ({
|
||||
},
|
||||
comboboxTitle: {
|
||||
fontSize: theme.fontSize.lg,
|
||||
fontWeight: theme.fontWeight.semibold,
|
||||
fontWeight: theme.fontWeight.medium,
|
||||
color: theme.colors.foreground,
|
||||
textAlign: "center",
|
||||
textAlign: "left",
|
||||
},
|
||||
comboboxScrollContent: {
|
||||
paddingBottom: theme.spacing[8],
|
||||
paddingHorizontal: theme.spacing[1],
|
||||
paddingHorizontal: theme.spacing[2],
|
||||
paddingTop: theme.spacing[1],
|
||||
},
|
||||
desktopOverlay: {
|
||||
flex: 1,
|
||||
@@ -638,7 +650,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
backgroundColor: theme.colors.surface0,
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.borderAccent,
|
||||
borderColor: theme.colors.border,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: 0.2,
|
||||
|
||||
@@ -458,6 +458,9 @@ export function DropdownMenuItem({
|
||||
label = successLabel;
|
||||
}
|
||||
|
||||
const trailingContent =
|
||||
trailing ?? (!showSelectedCheck && selected ? <Check size={16} color={theme.colors.foregroundMuted} /> : null);
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
testID={testID}
|
||||
@@ -473,8 +476,12 @@ export function DropdownMenuItem({
|
||||
style={({ pressed, hovered }) => [
|
||||
styles.item,
|
||||
selected ? (selectedVariant === "accent" ? styles.itemSelectedAccent : styles.itemSelected) : null,
|
||||
selected && (hovered || pressed) && selectedVariant !== "accent"
|
||||
? styles.itemSelectedInteractive
|
||||
: null,
|
||||
isDisabled ? styles.itemDisabled : null,
|
||||
(hovered || pressed) && !isDisabled ? styles.itemHovered : null,
|
||||
hovered && !pressed && !isDisabled ? styles.itemHovered : null,
|
||||
pressed && !isDisabled ? styles.itemPressed : null,
|
||||
]}
|
||||
>
|
||||
{showSelectedCheck ? (
|
||||
@@ -507,7 +514,7 @@ export function DropdownMenuItem({
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
{trailing ? <View style={styles.trailingSlot}>{trailing}</View> : null}
|
||||
{trailingContent ? <View style={styles.trailingSlot}>{trailingContent}</View> : null}
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
@@ -565,12 +572,20 @@ const styles = StyleSheet.create((theme) => ({
|
||||
gap: theme.spacing[2],
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
paddingVertical: theme.spacing[2],
|
||||
borderWidth: theme.borderWidth[1],
|
||||
borderColor: "transparent",
|
||||
},
|
||||
itemHovered: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
itemPressed: {
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
itemSelected: {
|
||||
backgroundColor: theme.colors.surface2,
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
itemSelectedInteractive: {
|
||||
backgroundColor: theme.colors.surface1,
|
||||
},
|
||||
itemSelectedAccent: {
|
||||
backgroundColor: theme.colors.accent,
|
||||
|
||||
Reference in New Issue
Block a user