import { View, Text, Pressable, Image, Platform, ActivityIndicator, } from "react-native"; import { useQueries } from "@tanstack/react-query"; import { useCallback, useMemo, useState, useEffect, useRef, type ReactElement, type MutableRefObject, } from "react"; import { router, usePathname } from "expo-router"; import { StyleSheet, UnistylesRuntime, useUnistyles, } from "react-native-unistyles"; import { type GestureType } from "react-native-gesture-handler"; import { Archive, Check, ChevronDown } from "lucide-react-native"; import { DraggableList, type DraggableRenderItemInfo, } from "./draggable-list"; import { getHostRuntimeStore, isHostRuntimeConnected, } from "@/runtime/host-runtime"; import { buildAgentNavigationKey, startNavigationTiming, } from "@/utils/navigation-timing"; import { buildHostAgentDetailRoute, parseHostAgentRouteFromPathname, } from "@/utils/host-routes"; import { projectIconQueryKey } from "@/hooks/use-project-icon-query"; import { type SidebarAgentListEntry, type SidebarProjectFilterOption, } from "@/hooks/use-sidebar-agents-list"; import type { ProjectIcon } from "@server/shared/messages"; import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store"; import { getIsTauri } from "@/constants/layout"; import { AgentStatusDot } from "@/components/agent-status-dot"; import { Combobox } from "@/components/ui/combobox"; import { parseSidebarAgentKey } from "@/utils/sidebar-shortcuts"; import { parseRepoNameFromRemoteUrl } from "@/utils/agent-grouping"; import { formatTimeAgo } from "@/utils/time"; import { isSidebarActiveAgent } from "@/utils/sidebar-agent-state"; import { useArchiveAgent } from "@/hooks/use-archive-agent"; type EntryData = SidebarAgentListEntry; function toProjectIconDataUri(icon: ProjectIcon | null): string | null { if (!icon) { return null; } return `data:${icon.mimeType};base64,${icon.data}`; } interface SidebarAgentListProps { isOpen?: boolean; entries: SidebarAgentListEntry[]; projectFilterOptions: SidebarProjectFilterOption[]; selectedProjectFilterKeys: string[]; onSelectedProjectFilterKeysChange: (keys: string[]) => void; isRefreshing?: boolean; onRefresh?: () => void; selectedAgentId?: string; onAgentSelect?: () => void; listFooterComponent?: ReactElement | null; /** Gesture ref for coordinating with parent gestures (e.g., sidebar close) */ parentGestureRef?: MutableRefObject; } interface ProjectFilterOptionRowProps { option: SidebarProjectFilterOption; selected: boolean; iconDataUri: string | null; displayName: string; onToggle: (projectKey: string) => void; } function ProjectFilterOptionRow({ option, selected, iconDataUri, displayName, onToggle, }: ProjectFilterOptionRowProps) { const { theme } = useUnistyles(); return ( [ styles.filterOption, hovered && styles.filterOptionHovered, pressed && styles.filterOptionPressed, ]} onPress={() => onToggle(option.projectKey)} > {iconDataUri ? ( ) : ( {displayName.charAt(0).toUpperCase()} )} {displayName} {option.activeCount > 0 ? ( {option.activeCount} ) : null} {selected ? : null} ); } interface SidebarAgentRowProps { entry: SidebarAgentListEntry; projectDisplayName: string; projectIconDataUri: string | null; isSelected: boolean; isInSelectionMode: boolean; isBatchSelected: boolean; isArchiving: boolean; shortcutNumber: number | null; onPress: () => void; onLongPress: () => void; onArchive: () => Promise; onToggleBatch: () => void; } function resolveBranchLabel(entry: SidebarAgentListEntry): string | null { const checkout = entry.project.checkout; if (!checkout.isGit) { return null; } const branch = checkout.currentBranch; if (!branch || branch === "HEAD" || branch === "main") { return null; } return branch; } function SidebarAgentRow({ entry, projectDisplayName, projectIconDataUri, isSelected, isInSelectionMode, isBatchSelected, isArchiving, shortcutNumber, onPress, onLongPress, onArchive, onToggleBatch, }: SidebarAgentRowProps) { const { theme } = useUnistyles(); const [isHovered, setIsHovered] = useState(false); const [isArchiveHovered, setIsArchiveHovered] = useState(false); const [isArchiveConfirmVisible, setIsArchiveConfirmVisible] = useState(false); const hoverOutTimeoutRef = useRef | null>(null); const branchLabel = resolveBranchLabel(entry); const relativeCreatedAt = formatTimeAgo(entry.agent.createdAt); const isActive = isSidebarActiveAgent({ status: entry.agent.status, requiresAttention: entry.agent.requiresAttention, attentionReason: entry.agent.attentionReason, }); const shouldApplyInactiveStyles = !isActive && !isSelected; const showArchive = !isInSelectionMode && shortcutNumber === null && (isHovered || isArchiveHovered || isArchiveConfirmVisible || isArchiving); const clearHoverOutTimeout = useCallback(() => { if (!hoverOutTimeoutRef.current) { return; } clearTimeout(hoverOutTimeoutRef.current); hoverOutTimeoutRef.current = null; }, []); useEffect(() => { return () => clearHoverOutTimeout(); }, [clearHoverOutTimeout]); useEffect(() => { if (!isArchiving) { setIsArchiveConfirmVisible(false); } }, [isArchiving]); const handleHoverIn = useCallback(() => { clearHoverOutTimeout(); setIsHovered(true); }, [clearHoverOutTimeout]); const handleHoverOut = useCallback(() => { clearHoverOutTimeout(); hoverOutTimeoutRef.current = setTimeout(() => { setIsHovered(false); setIsArchiveHovered(false); setIsArchiveConfirmVisible(false); }, 50); }, [clearHoverOutTimeout]); return ( [ styles.agentItem, isSelected && styles.agentItemSelected, isHovered && styles.agentItemHovered, pressed && styles.agentItemPressed, ]} onPress={onPress} onLongPress={onLongPress} onPressIn={() => { if (Platform.OS !== "web") { return; } handleHoverIn(); }} onHoverIn={handleHoverIn} onHoverOut={handleHoverOut} testID={`agent-row-${entry.agent.serverId}-${entry.agent.id}`} > {isInSelectionMode ? ( { event.stopPropagation(); onToggleBatch(); }} style={[ styles.checkbox, isBatchSelected && styles.checkboxSelected, ]} > {isBatchSelected ? ( ) : null} ) : ( )} {entry.agent.title || "New agent"} {showArchive ? ( { clearHoverOutTimeout(); setIsHovered(true); setIsArchiveHovered(true); }} onHoverOut={() => { setIsArchiveHovered(false); }} onPress={(event) => { event.stopPropagation(); if (isArchiving) { return; } if (!isArchiveConfirmVisible) { setIsArchiveConfirmVisible(true); return; } void onArchive(); }} style={styles.archiveButton} disabled={isArchiving} testID={ isArchiveConfirmVisible || isArchiving ? `agent-archive-confirm-${entry.agent.serverId}-${entry.agent.id}` : `agent-archive-${entry.agent.serverId}-${entry.agent.id}` } > {({ hovered: archiveHovered }) => isArchiving ? ( ) : isArchiveConfirmVisible ? ( ) : ( ) } ) : ( {relativeCreatedAt} )} {shortcutNumber !== null && !isInSelectionMode ? ( {shortcutNumber} ) : null} {projectIconDataUri ? ( ) : ( {projectDisplayName.charAt(0).toUpperCase()} )} {projectDisplayName} {branchLabel ? ( {branchLabel} ) : null} ); } function deriveShortcutIndexByAgentKey(sidebarShortcutAgentKeys: string[]) { const map = new Map(); for (let i = 0; i < sidebarShortcutAgentKeys.length; i += 1) { const key = sidebarShortcutAgentKeys[i]; if (!key) continue; map.set(key, i + 1); } return map; } function resolveSelectedProjectLabel(input: { selectedProjectFilterKeys: string[]; projectFilterOptions: SidebarProjectFilterOption[]; }): string { if (input.selectedProjectFilterKeys.length === 0) { return "Project"; } if (input.selectedProjectFilterKeys.length === 1) { const selected = input.projectFilterOptions.find( (option) => option.projectKey === input.selectedProjectFilterKeys[0] ); if (selected) { return deriveProjectDisplayName({ projectKey: selected.projectKey, projectName: selected.projectName, remoteUrl: null, }); } return deriveProjectDisplayName({ projectKey: input.selectedProjectFilterKeys[0] ?? "", projectName: "", remoteUrl: null, }); } return "Projects"; } function deriveProjectDisplayName(input: { projectKey: string; projectName: string; remoteUrl: string | null; }): string { const remoteRepoName = parseRepoNameFromRemoteUrl(input.remoteUrl); if (remoteRepoName) { return remoteRepoName; } const githubPrefix = "remote:github.com/"; if (input.projectKey.startsWith(githubPrefix)) { return input.projectKey.slice(githubPrefix.length); } if (input.projectKey.startsWith("remote:")) { const withoutPrefix = input.projectKey.slice("remote:".length); const slashIdx = withoutPrefix.indexOf("/"); if (slashIdx >= 0) { const remotePath = withoutPrefix.slice(slashIdx + 1).trim(); if (remotePath.length > 0) { return remotePath; } } return withoutPrefix; } const trimmedProjectName = input.projectName.trim(); if (trimmedProjectName.length > 0) { return trimmedProjectName; } return input.projectKey; } export function SidebarAgentList({ isOpen = true, entries, projectFilterOptions, selectedProjectFilterKeys, onSelectedProjectFilterKeysChange, isRefreshing = false, onRefresh, selectedAgentId, onAgentSelect, listFooterComponent, parentGestureRef, }: SidebarAgentListProps) { const { theme } = useUnistyles(); const pathname = usePathname(); const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm"; const showDesktopWebScrollbar = Platform.OS === "web" && !isMobile; const [isProjectFilterOpen, setIsProjectFilterOpen] = useState(false); const projectFilterAnchorRef = useRef(null); const [isSelectionMode, setIsSelectionMode] = useState(false); const [selectedBatchKeys, setSelectedBatchKeys] = useState>(new Set()); const { archiveAgent, isArchivingAgent } = useArchiveAgent(); const altDown = useKeyboardShortcutsStore((s) => s.altDown); const cmdOrCtrlDown = useKeyboardShortcutsStore((s) => s.cmdOrCtrlDown); const sidebarShortcutAgentKeys = useKeyboardShortcutsStore( (s) => s.sidebarShortcutAgentKeys ); const isTauri = getIsTauri(); const showShortcutBadges = !isSelectionMode && (altDown || (isTauri && cmdOrCtrlDown)); const shortcutIndexByAgentKey = useMemo( () => deriveShortcutIndexByAgentKey(sidebarShortcutAgentKeys), [sidebarShortcutAgentKeys] ); const selectedProjectLabel = useMemo( () => resolveSelectedProjectLabel({ selectedProjectFilterKeys, projectFilterOptions }), [projectFilterOptions, selectedProjectFilterKeys] ); const selectedProjectOption = useMemo(() => { if (selectedProjectFilterKeys.length !== 1) { return null; } return ( projectFilterOptions.find((option) => option.projectKey === selectedProjectFilterKeys[0]) ?? null ); }, [projectFilterOptions, selectedProjectFilterKeys]); const showProjectFilters = projectFilterOptions.length > 0; const projectIconRequests = useMemo(() => { if (!isOpen) { return []; } const unique = new Map(); for (const option of projectFilterOptions) { if (!option.serverId || !option.workingDir) { continue; } unique.set(`${option.serverId}:${option.workingDir}`, { serverId: option.serverId, cwd: option.workingDir, }); } for (const entry of entries) { const serverId = entry.agent.serverId; const cwd = entry.project.checkout.cwd; if (!serverId || !cwd) { continue; } unique.set(`${serverId}:${cwd}`, { serverId, cwd }); } return Array.from(unique.values()); }, [entries, isOpen, projectFilterOptions]); const projectIconQueries = useQueries({ queries: projectIconRequests.map((request) => ({ queryKey: projectIconQueryKey(request.serverId, request.cwd), queryFn: async () => { const client = getHostRuntimeStore().getClient(request.serverId); if (!client) { return null; } const result = await client.requestProjectIcon(request.cwd); return result.icon; }, select: toProjectIconDataUri, enabled: Boolean( isOpen && getHostRuntimeStore().getClient(request.serverId) && isHostRuntimeConnected( getHostRuntimeStore().getSnapshot(request.serverId) ) && request.cwd ), staleTime: Infinity, gcTime: 1000 * 60 * 60, refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false, })), }); const projectIconByQueryKey = useMemo(() => { const map = new Map(); for (let i = 0; i < projectIconRequests.length; i += 1) { const request = projectIconRequests[i]; if (!request) { continue; } const dataUri = projectIconQueries[i]?.data ?? null; map.set(`${request.serverId}:${request.cwd}`, dataUri); } return map; }, [projectIconQueries, projectIconRequests]); const projectIconByProjectKey = useMemo(() => { const map = new Map(); for (const option of projectFilterOptions) { map.set( option.projectKey, projectIconByQueryKey.get(`${option.serverId}:${option.workingDir}`) ?? null ); } for (const entry of entries) { if (map.has(entry.project.projectKey)) { continue; } map.set( entry.project.projectKey, projectIconByQueryKey.get( `${entry.agent.serverId}:${entry.project.checkout.cwd}` ) ?? null ); } return map; }, [entries, projectIconByQueryKey, projectFilterOptions]); const selectedProjectIconUri = useMemo(() => { if (!selectedProjectOption) { return null; } return projectIconByProjectKey.get(selectedProjectOption.projectKey) ?? null; }, [projectIconByProjectKey, selectedProjectOption]); const handleToggleProject = useCallback( (projectKey: string) => { const next = new Set(selectedProjectFilterKeys); if (next.has(projectKey)) { next.delete(projectKey); } else { next.add(projectKey); } onSelectedProjectFilterKeysChange(Array.from(next)); }, [onSelectedProjectFilterKeysChange, selectedProjectFilterKeys] ); const handleClearProjectFilter = useCallback(() => { onSelectedProjectFilterKeysChange([]); }, [onSelectedProjectFilterKeysChange]); const handleAgentPress = useCallback( (entry: SidebarAgentListEntry) => { const key = `${entry.agent.serverId}:${entry.agent.id}`; if (isSelectionMode) { setSelectedBatchKeys((prev) => { const next = new Set(prev); if (next.has(key)) { next.delete(key); } else { next.add(key); } return next; }); return; } const navigationKey = buildAgentNavigationKey(entry.agent.serverId, entry.agent.id); startNavigationTiming(navigationKey, { from: "home", to: "agent", params: { serverId: entry.agent.serverId, agentId: entry.agent.id }, }); const shouldReplace = Boolean(parseHostAgentRouteFromPathname(pathname)); const navigate = shouldReplace ? router.replace : router.push; onAgentSelect?.(); navigate(buildHostAgentDetailRoute(entry.agent.serverId, entry.agent.id) as any); }, [isSelectionMode, onAgentSelect, pathname] ); const handleAgentLongPress = useCallback((entry: SidebarAgentListEntry) => { const key = `${entry.agent.serverId}:${entry.agent.id}`; setIsSelectionMode(true); setSelectedBatchKeys(new Set([key])); }, []); const handleArchiveSingle = useCallback( async (entry: SidebarAgentListEntry): Promise => { await archiveAgent({ serverId: entry.agent.serverId, agentId: entry.agent.id, }).catch((error) => { console.warn("[archive_agent] failed", error); }); }, [archiveAgent] ); const handleArchiveBatch = useCallback(() => { if (selectedBatchKeys.size === 0) { setIsSelectionMode(false); return; } const requests: Promise[] = []; for (const key of selectedBatchKeys) { const parsed = parseSidebarAgentKey(key); if (!parsed) { continue; } requests.push( archiveAgent({ serverId: parsed.serverId, agentId: parsed.agentId, }).catch((error) => { console.warn("[archive_agent_batch] failed", { key, error }); }) ); } void Promise.all(requests).finally(() => { setSelectedBatchKeys(new Set()); setIsSelectionMode(false); }); }, [archiveAgent, selectedBatchKeys]); const handleSelectionBack = useCallback(() => { setSelectedBatchKeys(new Set()); setIsSelectionMode(false); }, []); const renderRow = useCallback( ({ item }: DraggableRenderItemInfo) => { const key = `${item.agent.serverId}:${item.agent.id}`; const projectDisplayName = deriveProjectDisplayName({ projectKey: item.project.projectKey, projectName: item.project.projectName, remoteUrl: item.project.checkout.remoteUrl, }); return ( handleAgentPress(item)} onLongPress={() => handleAgentLongPress(item)} onArchive={() => handleArchiveSingle(item)} onToggleBatch={() => { setSelectedBatchKeys((prev) => { const next = new Set(prev); if (next.has(key)) { next.delete(key); } else { next.add(key); } return next; }); }} /> ); }, [ handleAgentLongPress, handleAgentPress, handleArchiveSingle, isArchivingAgent, isSelectionMode, selectedAgentId, selectedBatchKeys, shortcutIndexByAgentKey, showShortcutBadges, projectIconByProjectKey, ] ); const keyExtractor = useCallback( (entry: EntryData) => `${entry.agent.serverId}:${entry.agent.id}`, [] ); return ( {showProjectFilters ? ( [ styles.filterTrigger, (selectedProjectFilterKeys.length > 0 || hovered || pressed) && styles.filterTriggerActive, ]} onPress={() => setIsProjectFilterOpen(true)} > {({ hovered = false, pressed }) => { const isInteracting = hovered || pressed; const showActiveForeground = selectedProjectFilterKeys.length > 0 || isInteracting; return ( <> {selectedProjectFilterKeys.length === 1 && selectedProjectIconUri ? ( ) : selectedProjectFilterKeys.length > 1 ? ( {selectedProjectFilterKeys.length} ) : null} {selectedProjectLabel} ); }} {selectedProjectFilterKeys.length > 0 ? ( Clear ) : null} {}} title="Filter by project" placeholder="Search projects" searchPlaceholder="Search projects" desktopPlacement="bottom-start" open={isProjectFilterOpen} onOpenChange={setIsProjectFilterOpen} anchorRef={projectFilterAnchorRef} > {projectFilterOptions.length === 0 ? ( No projects ) : ( projectFilterOptions.map((option) => ( )) )} ) : null} {}} showsVerticalScrollIndicator={false} enableDesktopWebScrollbar={showDesktopWebScrollbar} ListFooterComponent={listFooterComponent} refreshing={isRefreshing} onRefresh={onRefresh} simultaneousGestureRef={parentGestureRef} /> {isSelectionMode ? ( Back Archive ) : null} ); } const styles = StyleSheet.create((theme) => ({ container: { flex: 1, }, filtersRow: { paddingHorizontal: theme.spacing[3], paddingTop: theme.spacing[2], paddingBottom: theme.spacing[2], flexDirection: "row", alignItems: "center", gap: theme.spacing[2], }, filterTrigger: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2], alignSelf: "flex-start", maxWidth: 260, borderWidth: 1, borderColor: theme.colors.border, borderRadius: theme.borderRadius.full, paddingHorizontal: theme.spacing[3], paddingVertical: theme.spacing[1], backgroundColor: theme.colors.surface1, }, filterTriggerActive: { borderColor: theme.colors.borderAccent, }, filterTriggerText: { color: theme.colors.foreground, fontSize: theme.fontSize.sm, maxWidth: 180, }, filterTriggerTextMuted: { color: theme.colors.foregroundMuted, }, selectedProjectIcon: { width: theme.iconSize.sm, height: theme.iconSize.sm, borderRadius: theme.borderRadius.sm, }, projectCountBadge: { minWidth: theme.iconSize.md, height: theme.iconSize.md, borderRadius: theme.borderRadius.full, alignItems: "center", justifyContent: "center", paddingHorizontal: 4, backgroundColor: theme.colors.surface2, }, projectCountBadgeText: { fontSize: theme.fontSize.xs, color: theme.colors.foregroundMuted, }, clearFilterButton: { paddingHorizontal: theme.spacing[2], paddingVertical: theme.spacing[1], }, clearFilterText: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, }, filterOptionsList: { gap: theme.spacing[1], }, filterEmptyText: { color: theme.colors.foregroundMuted, textAlign: "center", paddingVertical: theme.spacing[4], }, filterOption: { paddingVertical: theme.spacing[2], paddingHorizontal: theme.spacing[2], borderRadius: 0, flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: theme.spacing[2], }, filterOptionHovered: { backgroundColor: theme.colors.surface1, }, filterOptionPressed: { backgroundColor: theme.colors.surface2, }, filterOptionLeft: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2], flex: 1, minWidth: 0, }, filterOptionRight: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2], flexShrink: 0, }, filterOptionLabel: { color: theme.colors.foreground, fontSize: theme.fontSize.sm, flex: 1, }, filterOptionCount: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.xs, }, projectIcon: { width: theme.iconSize.sm, height: theme.iconSize.sm, borderRadius: theme.borderRadius.sm, }, projectIconFallback: { width: theme.iconSize.sm, height: theme.iconSize.sm, borderRadius: theme.borderRadius.sm, borderWidth: 1, borderColor: theme.colors.border, alignItems: "center", justifyContent: "center", }, projectIconFallbackInactive: { opacity: 0.5, }, projectIconFallbackText: { color: theme.colors.foregroundMuted, fontSize: 9, }, list: { flex: 1, }, listContent: { paddingHorizontal: theme.spacing[2], paddingBottom: theme.spacing[4], }, listContentSelectionMode: { paddingBottom: theme.spacing[16], }, agentItem: { paddingVertical: theme.spacing[2], paddingHorizontal: theme.spacing[3], borderRadius: theme.borderRadius.lg, marginBottom: theme.spacing[1], }, agentItemSelected: { backgroundColor: theme.colors.surface2, }, agentItemHovered: { backgroundColor: theme.colors.surface1, }, agentItemPressed: { backgroundColor: theme.colors.surface2, }, agentRowTop: { flexDirection: "row", alignItems: "center", gap: theme.spacing[2], minHeight: 20, }, checkbox: { width: theme.iconSize.md, height: theme.iconSize.md, borderRadius: theme.borderRadius.sm, borderWidth: 1, borderColor: theme.colors.border, alignItems: "center", justifyContent: "center", }, checkboxSelected: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary, }, agentTitle: { flex: 1, fontSize: theme.fontSize.base, fontWeight: theme.fontWeight.normal, color: theme.colors.foreground, opacity: 1, }, agentTitleInactive: { opacity: 0.8, }, agentTitleSelected: { opacity: 1, }, relativeTimeText: { color: theme.colors.foregroundMuted, opacity: 0.78, fontSize: theme.fontSize.xs, }, shortcutBadge: { minWidth: 20, height: 20, borderRadius: theme.borderRadius.md, borderWidth: 1, borderColor: theme.colors.border, alignItems: "center", justifyContent: "center", paddingHorizontal: theme.spacing[1], }, shortcutBadgeText: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.xs, }, archiveButton: { minWidth: 24, height: 20, borderRadius: theme.borderRadius.md, borderWidth: 1, borderColor: theme.colors.border, alignItems: "center", justifyContent: "center", paddingHorizontal: theme.spacing[1], }, agentMetaRow: { marginTop: theme.spacing[1], flexDirection: "row", alignItems: "center", gap: theme.spacing[2], }, agentMetaProjectIcon: { width: theme.iconSize.sm, height: theme.iconSize.sm, borderRadius: theme.borderRadius.sm, }, agentMetaProjectIconInactive: { opacity: 0.5, }, agentMetaProjectName: { color: theme.colors.foreground, opacity: 0.78, fontSize: theme.fontSize.xs, flexShrink: 0, }, agentMetaBranchBadge: { borderRadius: theme.borderRadius.full, borderWidth: 1, borderColor: theme.colors.border, paddingHorizontal: theme.spacing[1], paddingVertical: 1, flexShrink: 1, minWidth: 0, }, agentMetaBranchBadgeSelected: { borderColor: theme.colors.borderAccent, }, agentMetaBranchText: { color: theme.colors.foreground, opacity: 0.76, fontSize: theme.fontSize.xs, flexShrink: 1, minWidth: 0, }, selectionBar: { position: "absolute", left: theme.spacing[2], right: theme.spacing[2], bottom: theme.spacing[2], borderRadius: theme.borderRadius.xl, borderWidth: 1, borderColor: theme.colors.border, backgroundColor: theme.colors.surface2, padding: theme.spacing[2], flexDirection: "row", gap: theme.spacing[2], }, selectionAction: { flex: 1, borderRadius: theme.borderRadius.lg, borderWidth: 1, borderColor: theme.colors.border, alignItems: "center", justifyContent: "center", paddingVertical: theme.spacing[2], backgroundColor: theme.colors.surface1, }, selectionActionText: { color: theme.colors.foreground, fontSize: theme.fontSize.sm, }, selectionArchiveAction: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary, }, selectionArchiveActionDisabled: { opacity: 0.5, }, selectionArchiveActionText: { color: theme.colors.primaryForeground, fontSize: theme.fontSize.sm, }, }));