Files
paseo/packages/app/src/components/ui/combobox-trigger.tsx
T
Mohamed Boudra 36a136d811 Add shared trigger components and horizontal desktop workspace arguments
- Add DropdownTrigger and ComboboxTrigger with an overridable chevron slot and a 1 px translateY caret nudge for consistent vertical alignment.

- Convert text-based dropdown/combobox triggers across model selector, agent controls, mode control, settings, and new workspace to use the shared components.

- Lay out New Workspace arguments horizontally on desktop without labels while keeping the mobile vertical stack; align the project icon left edge with the title.
2026-06-16 14:56:07 +07:00

72 lines
1.9 KiB
TypeScript

import { forwardRef, useCallback, type ReactElement, type ReactNode } from "react";
import {
Pressable,
View,
type PressableProps,
type PressableStateCallbackType,
type ViewStyle,
type StyleProp,
} from "react-native";
import { StyleSheet, withUnistyles } from "react-native-unistyles";
import { ChevronDown } from "lucide-react-native";
import { ICON_SIZE, type Theme } from "@/styles/theme";
const ThemedChevronDown = withUnistyles(ChevronDown);
const chevronColorMapping = (theme: Theme) => ({
color: theme.colors.foregroundMuted,
});
interface TriggerState {
pressed: boolean;
hovered: boolean;
}
type TriggerStyleProp = StyleProp<ViewStyle> | ((state: TriggerState) => StyleProp<ViewStyle>);
interface ComboboxTriggerProps extends Omit<PressableProps, "style" | "children"> {
style?: TriggerStyleProp;
children?: ReactNode;
chevron?: ReactNode | null;
}
export const ComboboxTrigger = forwardRef<View, ComboboxTriggerProps>(function ComboboxTrigger(
{ children, chevron, style, ...props },
ref,
): ReactElement {
const pressableStyle = useCallback(
({ pressed, hovered = false }: PressableStateCallbackType & { hovered?: boolean }) => {
if (typeof style === "function") {
return style({ pressed, hovered });
}
return style;
},
[style],
);
return (
<Pressable ref={ref} collapsable={false} style={pressableStyle} {...props}>
<View style={styles.row}>
{children}
{chevron !== null &&
(chevron ?? (
<View style={styles.chevronContainer}>
<ThemedChevronDown size={ICON_SIZE.sm} uniProps={chevronColorMapping} />
</View>
))}
</View>
</Pressable>
);
});
const styles = StyleSheet.create((theme) => ({
row: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[1],
},
chevronContainer: {
transform: [{ translateY: 1 }],
},
}));