diff --git a/packages/app/src/components/ui/dropdown-menu.tsx b/packages/app/src/components/ui/dropdown-menu.tsx index 9b0c3ecb3..34e4b2c79 100644 --- a/packages/app/src/components/ui/dropdown-menu.tsx +++ b/packages/app/src/components/ui/dropdown-menu.tsx @@ -34,6 +34,8 @@ import { useWebScrollbarStyle } from "@/hooks/use-web-scrollbar-style"; // Action status for menu items with loading/success feedback export type ActionStatus = "idle" | "pending" | "success"; +const DROPDOWN_SCROLL_CONTENT_STYLE = { flexGrow: 1 } as const; + type Placement = "top" | "bottom" | "left" | "right"; type Alignment = "start" | "center" | "end"; @@ -432,6 +434,20 @@ export function DropdownMenuContent({ ...(typeof maxWidth === "number" ? { maxWidth } : null), }; + const contentStyle = useMemo( + () => [ + styles.content, + resolvedWidthStyle, + { + position: "absolute" as const, + top: position?.y ?? -9999, + left: position?.x ?? -9999, + transformOrigin: getTransformOrigin(actualPlacement, align), + }, + ], + [resolvedWidthStyle, position?.x, position?.y, actualPlacement, align], + ); + return ( {children} @@ -492,8 +499,9 @@ export function DropdownMenuLabel({ style, testID, }: PropsWithChildren<{ style?: ViewStyle | ViewStyle[]; testID?: string }>): ReactElement { + const labelContainerStyle = useMemo(() => [styles.labelContainer, style], [style]); return ( - + {children} ); @@ -506,7 +514,8 @@ export function DropdownMenuSeparator({ style?: ViewStyle; testID?: string; }): ReactElement { - return ; + const separatorStyle = useMemo(() => [styles.separator, style], [style]); + return ; } export function DropdownMenuHint({ @@ -618,6 +627,25 @@ export function DropdownMenuItem({ [selected, selectedVariant, isDisabled, muted], ); + const itemTextStyle = useMemo( + () => [ + styles.itemText, + destructive && !isSuccess ? styles.itemTextDestructive : null, + isSuccess ? styles.itemTextSuccess : null, + selected && selectedVariant === "accent" ? styles.itemTextSelectedAccent : null, + muted && !isDisabled ? styles.itemTextMuted : null, + ], + [destructive, isSuccess, selected, selectedVariant, muted, isDisabled], + ); + + const itemDescriptionStyle = useMemo( + () => [ + styles.itemDescription, + selected && selectedVariant === "accent" ? styles.itemDescriptionSelectedAccent : null, + ], + [selected, selectedVariant], + ); + const content = ( {leadingContent} : null} - + {label} {description && !isPending && !isSuccess ? ( - + {description} ) : null} diff --git a/packages/app/src/screens/workspace/workspace-tab-presentation.tsx b/packages/app/src/screens/workspace/workspace-tab-presentation.tsx index 717391f8e..0be0cd4b5 100644 --- a/packages/app/src/screens/workspace/workspace-tab-presentation.tsx +++ b/packages/app/src/screens/workspace/workspace-tab-presentation.tsx @@ -130,10 +130,34 @@ export function WorkspaceTabIcon({ bucket: presentation.statusBucket, }); const Icon = presentation.icon; + const agentIconWrapperStyle = useMemo( + () => [styles.agentIconWrapper, { width: size, height: size }], + [size], + ); + const statusDotStyle = useMemo( + () => [ + styles.statusDot, + { + backgroundColor: statusDotColor ?? undefined, + borderColor: statusDotBorderColor ?? theme.colors.surface0, + width: statusDotSize, + height: statusDotSize, + right: statusDotOffset, + bottom: statusDotOffset, + }, + ], + [ + statusDotColor, + statusDotBorderColor, + theme.colors.surface0, + statusDotSize, + statusDotOffset, + ], + ); if (shouldShowLoader) { return ( - + + - {statusDotColor ? ( - - ) : null} + {statusDotColor ? : null} ); } @@ -191,8 +201,12 @@ export function WorkspaceTabOptionRow({ ], [active], ); + const optionRowStyle = useMemo( + () => [styles.optionRow, active && styles.optionRowActive], + [active], + ); return ( - +