Files
orca/mobile/src/components/MobileSegmentedControl.tsx
T
Kelvin Amoaba cf7423c8f4 feat(mobile): redesign the chat composer with file attachments and inline skills (#30359)
* refactor(native-chat): move the slash picker builder and upload chunking to shared

Mobile builds the same skill and command list as desktop.

* feat(mobile): redesign the chat composer with file attachments and inline skills

* fix(mobile): the composer field owns its input style

The page's font-size census cannot follow a style passed in as a prop.
2026-10-18 20:03:26 +00:00

78 lines
2.7 KiB
TypeScript

import { Pressable, StyleSheet, Text, View, type StyleProp, type ViewStyle } from 'react-native'
import { colors, radii, spacing, typography } from '../theme/mobile-theme'
export type MobileSegment<Value extends string> = { value: Value; label: string }
type Props<Value extends string> = {
segments: readonly MobileSegment<Value>[]
/** A value outside the segments selects none, e.g. one a newer host sent. */
selected: string | undefined
onSelect: (value: Value) => void
/** Prefixes each segment's testID with this, then the segment's value. */
testIDPrefix?: string
/** Segments share the full width instead of sizing to their labels. */
fill?: boolean
/** The track; its default color suits a panel-colored row. */
style?: StyleProp<ViewStyle>
/** Shown but not pickable, e.g. while the value it sets is locked. */
disabled?: boolean
}
/** A pick-one pill control; each segment reads as a radio button. */
export function MobileSegmentedControl<Value extends string>(props: Props<Value>) {
return (
<View
style={[styles.segmented, props.style, props.disabled && styles.disabled]}
accessibilityRole="radiogroup"
>
{props.segments.map((segment) => {
const active = segment.value === props.selected
return (
<Pressable
key={segment.value}
accessibilityRole="radio"
aria-checked={active}
accessibilityState={{ disabled: props.disabled === true }}
disabled={props.disabled}
accessibilityLabel={segment.label}
testID={props.testIDPrefix ? `${props.testIDPrefix}${segment.value}` : undefined}
onPress={() => props.onSelect(segment.value)}
style={[
styles.segment,
props.fill && styles.segmentFill,
active && styles.segmentActive
]}
>
<Text
style={[styles.segmentText, active && styles.segmentTextActive]}
numberOfLines={1}
>
{segment.label}
</Text>
</Pressable>
)
})}
</View>
)
}
const styles = StyleSheet.create({
segmented: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.bgBase,
borderRadius: radii.button,
padding: 2
},
segment: {
paddingHorizontal: spacing.md,
paddingVertical: 6,
borderRadius: radii.button - 1
},
segmentFill: { flex: 1, alignItems: 'center', paddingHorizontal: spacing.xs },
segmentActive: { backgroundColor: colors.bgRaised },
disabled: { opacity: 0.5 },
segmentText: { fontSize: typography.metaSize, color: colors.textSecondary, fontWeight: '600' },
segmentTextActive: { color: colors.textPrimary }
})