Files
native/src/components/RadioGroup.tsx
T
Linus Rath cf3f919fa2 feat: enhance SettingsScreen with dynamic localization and theming
- Integrated useColors hook for dynamic theming in SettingsScreen.
- Updated tab labels and titles to use localized strings.
- Refactored styles to utilize theme palette for consistent styling.
- Improved locale subscription to re-render labels on language change.

feat: implement useSheetDrag hook for bottom sheet gesture handling

- Added useSheetDrag hook to manage drag-to-dismiss functionality for bottom sheets.
- Configured pan responder for handling drag gestures and dismissing the sheet based on distance and velocity.

refactor: restructure color and token management

- Introduced useColors and useResolvedTheme hooks for better theme management.
- Separated light and dark color palettes for improved maintainability.
- Updated tokens to reflect new theming structure and ensure consistency across components.
2026-04-27 13:30:45 +02:00

77 lines
2.0 KiB
TypeScript

import React from 'react';
import { View, Text, Pressable, StyleSheet, ViewStyle } from 'react-native';
import { spacing, radius, typography, type ThemePalette } from '../theme/tokens';
import { useColors } from '../theme/colors';
interface RadioOption {
label: string;
value: string;
}
interface RadioGroupProps {
options: RadioOption[];
value: string;
onChange: (value: string) => void;
style?: ViewStyle;
}
/**
* Matches webmail RadioGroup (button variant):
* - container: flex gap-1.5
* - button: px-3 py-1.5 text-xs rounded-md
* - selected: bg-primary text-primary-foreground font-medium
* - unselected: bg-muted text-foreground
*/
export default function RadioGroup({ options, value, onChange, style }: RadioGroupProps) {
const c = useColors();
const styles = React.useMemo(() => makeStyles(c), [c]);
return (
<View style={[styles.container, style]}>
{options.map((opt) => {
const selected = opt.value === value;
return (
<Pressable
key={opt.value}
style={[styles.option, selected ? styles.optionSelected : styles.optionUnselected]}
onPress={() => onChange(opt.value)}
>
<Text style={[styles.optionText, selected ? styles.textSelected : styles.textUnselected]}>
{opt.label}
</Text>
</Pressable>
);
})}
</View>
);
}
function makeStyles(c: ThemePalette) {
return StyleSheet.create({
container: {
flexDirection: 'row',
gap: 6, // gap-1.5
},
option: {
paddingHorizontal: spacing.md, // px-3
paddingVertical: 6, // py-1.5
borderRadius: radius.sm, // rounded-md
},
optionSelected: {
backgroundColor: c.primary,
},
optionUnselected: {
backgroundColor: c.muted,
},
optionText: {
...typography.caption, // text-xs
},
textSelected: {
color: c.primaryForeground,
fontWeight: '500',
},
textUnselected: {
color: c.text,
},
});
}