// The pill and choice-row primitives the session-option card is built from, kept // beside it so the card file stays about layout and apply wiring. import { Pressable, StyleSheet, Text, View } from 'react-native' import { Check, ChevronDown, ChevronRight } from 'lucide-react-native' import { colors, radii, spacing, typography } from '../theme/mobile-theme' import type { SessionOptionDescriptor, SessionOptionValue } from '../../../src/shared/native-chat-session-options' /** Muted one-liner above a group — dispatch state, or why a row is locked. */ export function SessionOptionCaption({ children }: { children: string }): React.JSX.Element { return {children} } export function Pill({ label, accessibleName, disabled, onPress }: { label: string accessibleName: string disabled: boolean onPress: () => void }): React.JSX.Element { return ( [styles.pill, pressed && !disabled && styles.pressed]} onPress={onPress} disabled={disabled} hitSlop={6} > {label} ) } function ChoiceRow({ label, description, selected, disabled, grouped, divided, onPress }: { label: string description?: string selected: boolean disabled: boolean grouped: boolean divided: boolean onPress: () => void }): React.JSX.Element { return ( {selected ? : null} {label} {description ? ( {description} ) : null} ) } function ActionRow({ label, disabled, grouped, onPress }: { label: string disabled: boolean grouped: boolean onPress: () => void }): React.JSX.Element { return ( {label} ) } export function SessionOptionSummaryRow({ label, value, disabled, divided, onPress }: { label: string value: string disabled: boolean divided: boolean onPress: () => void }): React.JSX.Element { return ( [ styles.summaryRow, divided && styles.rowDivided, pressed && !disabled && styles.pressed, disabled && styles.rowDisabled ]} onPress={onPress} disabled={disabled} > {label} {value} ) } export function DescriptorRows({ descriptor, disabled, grouped = false, onSetOption, onInvokeAction }: { descriptor: SessionOptionDescriptor disabled: boolean grouped?: boolean onSetOption: (value: SessionOptionValue) => void onInvokeAction: () => void }): React.JSX.Element { const locked = disabled || !descriptor.settable // Why: flip-only without a baseline is an action — never claim On/Off. if (descriptor.action?.type === 'toggle-command') { return ( ) } // Why: agent-picker opens the TUI; it is not a set of radio choices. if (descriptor.action?.type === 'agent-picker') { return ( ) } // Unknown booleans leave both radios unselected instead of inventing truth. if (descriptor.kind.type === 'boolean') { const current = descriptor.kind.currentValue return ( <> {current === undefined ? ( Current value unknown — pick On or Off ) : null} onSetOption(true)} /> onSetOption(false)} /> ) } const { currentValue, choices } = descriptor.kind return ( <> {choices.map((choice, index) => ( onSetOption(choice.value)} /> ))} ) } const styles = StyleSheet.create({ pill: { flexDirection: 'row', alignItems: 'center', gap: 4, maxWidth: 180, minHeight: 28, paddingHorizontal: spacing.sm, paddingVertical: 4, borderRadius: radii.button, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.borderSubtle, backgroundColor: colors.bgRaised }, pillText: { color: colors.textSecondary, fontSize: typography.metaSize, fontWeight: '600', flexShrink: 1 }, pillTextDisabled: { color: colors.textMuted }, pressed: { opacity: 0.7 }, caption: { color: colors.textMuted, fontSize: typography.metaSize, paddingHorizontal: spacing.md, paddingBottom: spacing.xs }, row: { flexDirection: 'row', gap: spacing.sm, padding: spacing.sm, minHeight: 44, alignItems: 'center', borderRadius: radii.card, backgroundColor: colors.bgRaised, borderWidth: 1, borderColor: colors.borderSubtle, marginBottom: spacing.xs }, rowSelected: { borderColor: colors.statusGreen }, rowGrouped: { marginBottom: 0, borderWidth: 0, borderRadius: 0, backgroundColor: 'transparent' }, rowDivided: { borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: colors.borderSubtle }, rowDisabled: { opacity: 0.5 }, radio: { width: 18, height: 18, borderRadius: 9, borderWidth: 1.5, borderColor: colors.textMuted, alignItems: 'center', justifyContent: 'center' }, radioOn: { backgroundColor: colors.statusGreen, borderColor: colors.statusGreen }, rowBody: { flex: 1, gap: 2 }, rowLabel: { color: colors.textPrimary, fontSize: typography.bodySize, fontWeight: '600' }, rowDescription: { color: colors.textSecondary, fontSize: typography.metaSize }, summaryRow: { minHeight: 48, flexDirection: 'row', alignItems: 'center', gap: spacing.sm, paddingHorizontal: spacing.md, paddingVertical: spacing.sm }, summaryLabel: { flex: 1, color: colors.textPrimary, fontSize: typography.bodySize, fontWeight: '600' }, summaryValue: { maxWidth: 160, color: colors.textSecondary, fontSize: typography.bodySize } })