From ab89a0293f288d2a4239ba6d8f3760447f24528e Mon Sep 17 00:00:00 2001 From: Bartek Dybowski Date: Fri, 19 Jun 2026 11:03:07 +0200 Subject: [PATCH 1/8] refactor(radio-button): merge platform variants into one MD3 component --- example/src/Examples/RadioButtonExample.tsx | 17 +- .../src/Examples/RadioButtonGroupExample.tsx | 4 +- .../src/Examples/RadioButtonItemExample.tsx | 18 +- src/components/RadioButton/RadioButton.tsx | 163 ++++++- .../RadioButton/RadioButtonAndroid.tsx | 200 --------- src/components/RadioButton/RadioButtonIOS.tsx | 130 ------ .../RadioButton/RadioButtonItem.tsx | 18 +- src/components/RadioButton/index.ts | 6 - src/components/RadioButton/utils.ts | 53 --- .../RadioButton/RadioButton.test.tsx | 54 +-- .../RadioButton/RadioButtonItem.test.tsx | 31 -- .../__snapshots__/RadioButton.test.tsx.snap | 231 +++------- .../RadioButtonGroup.test.tsx.snap | 59 +-- .../RadioButtonItem.test.tsx.snap | 402 +----------------- .../__tests__/RadioButton/utils.test.tsx | 72 +++- src/index.tsx | 2 - 16 files changed, 307 insertions(+), 1153 deletions(-) delete mode 100644 src/components/RadioButton/RadioButtonAndroid.tsx delete mode 100644 src/components/RadioButton/RadioButtonIOS.tsx diff --git a/example/src/Examples/RadioButtonExample.tsx b/example/src/Examples/RadioButtonExample.tsx index 6ab1869dd9..b6f8a06da8 100644 --- a/example/src/Examples/RadioButtonExample.tsx +++ b/example/src/Examples/RadioButtonExample.tsx @@ -10,7 +10,7 @@ import { import ScreenWrapper from '../ScreenWrapper'; -type State = 'normal' | 'normal-ios' | 'normal-item' | 'custom'; +type State = 'normal' | 'normal-item' | 'custom'; const RadioButtonExample = () => { const [checked, setChecked] = React.useState('normal'); @@ -19,26 +19,15 @@ const RadioButtonExample = () => { setChecked('normal')}> - Normal - Material Design + Normal - - setChecked('normal-ios')}> - - Normal 2 - IOS - - - - - setChecked('custom')}> Custom diff --git a/example/src/Examples/RadioButtonGroupExample.tsx b/example/src/Examples/RadioButtonGroupExample.tsx index dc7977acb8..46efc44f78 100644 --- a/example/src/Examples/RadioButtonGroupExample.tsx +++ b/example/src/Examples/RadioButtonGroupExample.tsx @@ -24,11 +24,11 @@ const RadioButtonGroupExample = () => { Second - + Third - + diff --git a/example/src/Examples/RadioButtonItemExample.tsx b/example/src/Examples/RadioButtonItemExample.tsx index e640a1dd0a..5b068eb854 100644 --- a/example/src/Examples/RadioButtonItemExample.tsx +++ b/example/src/Examples/RadioButtonItemExample.tsx @@ -7,8 +7,6 @@ import ScreenWrapper from '../ScreenWrapper'; const RadioButtonItemExample = () => { const [checkedDefault, setCheckedDefault] = React.useState(true); - const [checkedAndroid, setCheckedAndroid] = React.useState(true); - const [checkedIOS, setCheckedIOS] = React.useState(true); const [checkedLeadingControl, setCheckedLeadingControl] = React.useState(true); const [checkedDisabled, setCheckedDisabled] = React.useState(true); @@ -17,25 +15,11 @@ const RadioButtonItemExample = () => { return ( setCheckedDefault(!checkedDefault)} value="default" /> - setCheckedAndroid(!checkedAndroid)} - value="android" - /> - setCheckedIOS(!checkedIOS)} - value="iOS" - /> & { /** * Value of the radio button */ @@ -22,7 +24,7 @@ export type Props = { /** * Function to execute on press. */ - onPress?: (e: GestureResponderEvent) => void; + onPress?: (param?: any) => void; /** * Custom color for unchecked radio. */ @@ -41,6 +43,8 @@ export type Props = { testID?: string; }; +const BORDER_WIDTH = 2; + /** * Radio buttons allow the selection a single option from a set. * @@ -71,16 +75,149 @@ export type Props = { * * export default MyComponent; * ``` + * + * @extends TouchableRipple props https://callstack.github.io/react-native-paper/docs/components/TouchableRipple */ -const RadioButton = ({ theme: themeOverrides, ...props }: Props) => { +const RadioButton = ({ + disabled, + onPress, + theme: themeOverrides, + value, + status, + testID, + ...rest +}: Props) => { const theme = useInternalTheme(themeOverrides); + const { current: borderAnim } = React.useRef( + new Animated.Value(BORDER_WIDTH) + ); + + const { current: radioAnim } = React.useRef( + new Animated.Value(1) + ); + + const isFirstRendering = React.useRef(true); + + const { scale } = theme.animation; + + React.useEffect(() => { + // Do not run animation on very first rendering + if (isFirstRendering.current) { + isFirstRendering.current = false; + return; + } - const Button = Platform.select({ - default: RadioButtonAndroid, - ios: RadioButtonIOS, - }); + if (status === 'checked') { + radioAnim.setValue(1.2); - return