Skip to content

Commit 577241d

Browse files
author
Artur Yorsh
committed
BREAKING: refactor Radio to new api
1 parent e9fc5a7 commit 577241d

File tree

5 files changed

+169
-665
lines changed

5 files changed

+169
-665
lines changed

src/components/ui/radio/radio.component.tsx

Lines changed: 37 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,35 @@ import {
1111
Platform,
1212
StyleProp,
1313
StyleSheet,
14-
TextStyle,
15-
TouchableOpacity,
1614
TouchableOpacityProps,
1715
View,
1816
ViewStyle,
1917
} from 'react-native';
18+
import { Overwrite } from 'utility-types';
19+
import {
20+
FalsyText,
21+
RenderProp,
22+
TouchableWithoutFeedback,
23+
WebEventResponder,
24+
WebEventResponderInstance,
25+
} from '../../devsupport';
2026
import {
2127
Interaction,
2228
styled,
2329
StyledComponentProps,
2430
StyleType,
25-
} from '@kitten/theme';
26-
import {
27-
Text,
28-
TextElement,
29-
} from '../text/text.component';
30-
import {
31-
isValidString,
32-
WebEventResponder,
33-
WebEventResponderInstance,
34-
} from '../support/services';
31+
} from '../../theme';
32+
import { TextProps } from '../text/text.component';
33+
34+
type RadioStyledProps = Overwrite<StyledComponentProps, {
35+
appearance?: 'default' | string;
36+
}>;
3537

36-
export interface RadioProps extends StyledComponentProps, TouchableOpacityProps {
37-
textStyle?: StyleProp<TextStyle>;
38-
text?: string;
38+
export interface RadioProps extends TouchableOpacityProps, RadioStyledProps {
3939
checked?: boolean;
40-
status?: string;
4140
onChange?: (selected: boolean) => void;
41+
text?: RenderProp<TextProps> | React.ReactText;
42+
status?: 'basic' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'control' | string;
4243
}
4344

4445
export type RadioElement = React.ReactElement<RadioProps>;
@@ -51,18 +52,16 @@ export type RadioElement = React.ReactElement<RadioProps>;
5152
* @property {boolean} checked - Determines whether component is checked.
5253
* Default is `false`.
5354
*
54-
* @property {boolean} disabled - Determines whether component is disabled.
55-
* Default is `false`.
56-
*
5755
* @property {string} status - Determines the status of the component.
5856
* Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`.
5957
* Default is `basic`.
6058
*
61-
* @property {string} text - Determines text of the component.
62-
*
63-
* @property {StyleProp<TextStyle>} textStyle - Customizes text style.
59+
* @property {string | (props: TextProps) => ReactElement} text - A string or a function component
60+
* to render near the radio.
61+
* If it is a function, it will be called with props provided by Eva.
62+
* Otherwise, renders a Text styled by Eva.
6463
*
65-
* @property {(selected: boolean) => void} onChange - Triggered on onChange value.
64+
* @property {(checked: boolean) => void} onChange - Called on radio value change.
6665
*
6766
* @property {TouchableOpacityProps} ...TouchableOpacityProps - Any props applied to TouchableOpacity component.
6867
*
@@ -118,7 +117,7 @@ export class RadioComponent extends React.Component<RadioProps> {
118117
}
119118
};
120119

121-
private getComponentStyle = (source: StyleType): StyleType => {
120+
private getComponentStyle = (source: StyleType) => {
122121
const {
123122
textMarginHorizontal,
124123
textFontFamily,
@@ -138,8 +137,6 @@ export class RadioComponent extends React.Component<RadioProps> {
138137
} = source;
139138

140139
return {
141-
container: {},
142-
highlightContainer: {},
143140
selectContainer: containerParameters,
144141
text: {
145142
marginHorizontal: textMarginHorizontal,
@@ -178,62 +175,34 @@ export class RadioComponent extends React.Component<RadioProps> {
178175
};
179176
};
180177

181-
private renderTextElement = (style: StyleType): TextElement => {
182-
const { text, textStyle } = this.props;
183-
184-
return (
185-
<Text
186-
key={0}
187-
style={[style, styles.text, textStyle]}>
188-
{text}
189-
</Text>
190-
);
191-
};
192-
193-
private renderComponentChildren = (style: StyleType): React.ReactNodeArray => {
194-
const { text } = this.props;
195-
196-
return [
197-
isValidString(text) && this.renderTextElement(style.text),
198-
];
199-
};
200-
201178
public render(): React.ReactElement<TouchableOpacityProps> {
202-
const { style, eva, disabled, ...derivedProps } = this.props;
179+
const { eva, style, text, disabled, ...touchableProps } = this.props;
180+
const evaStyle = this.getComponentStyle(eva.style);
203181

204-
const {
205-
container,
206-
highlightContainer,
207-
selectContainer,
208-
icon,
209-
highlight,
210-
...componentStyles
211-
} = this.getComponentStyle(eva.style);
212-
213-
const selectContainerStyle: StyleProp<ViewStyle> = [selectContainer, styles.selectContainer];
182+
const selectContainerStyle: StyleProp<ViewStyle> = [evaStyle.selectContainer, styles.selectContainer];
214183
const hitSlopInsets: Insets = this.createHitSlopInsets(selectContainerStyle);
215184

216-
const [textElement] = this.renderComponentChildren(componentStyles);
217-
218185
return (
219-
<TouchableOpacity
220-
activeOpacity={1.0}
221-
{...derivedProps}
186+
<TouchableWithoutFeedback
187+
{...touchableProps}
222188
{...this.webEventResponder.eventHandlers}
223-
style={[container, styles.container, webStyles.container, style]}
189+
style={[styles.container, webStyles.container, style]}
224190
disabled={disabled}
225191
hitSlop={hitSlopInsets}
226192
onPress={this.onPress}
227193
onPressIn={this.onPressIn}
228194
onPressOut={this.onPressOut}>
229-
<View style={[highlightContainer, styles.highlightContainer]}>
230-
<View style={[highlight, styles.highlight]}/>
195+
<View style={styles.highlightContainer}>
196+
<View style={[evaStyle.highlight, styles.highlight]}/>
231197
<View style={selectContainerStyle}>
232-
<View style={[icon, styles.icon]}/>
198+
<View style={evaStyle.icon}/>
233199
</View>
234200
</View>
235-
{textElement}
236-
</TouchableOpacity>
201+
<FalsyText
202+
style={evaStyle.text}
203+
component={text}
204+
/>
205+
</TouchableWithoutFeedback>
237206
);
238207
}
239208
}
@@ -251,11 +220,9 @@ const styles = StyleSheet.create({
251220
justifyContent: 'center',
252221
alignItems: 'center',
253222
},
254-
icon: {},
255223
highlight: {
256224
position: 'absolute',
257225
},
258-
text: {},
259226
});
260227

261228
const webStyles = Platform.OS === 'web' && StyleSheet.create({
Lines changed: 66 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,110 @@
1+
/**
2+
* @license
3+
* Copyright Akveo. All Rights Reserved.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*/
6+
17
import React from 'react';
2-
import { TouchableOpacity } from 'react-native';
38
import {
4-
render,
9+
Text,
10+
TouchableOpacity,
11+
} from 'react-native';
12+
import {
513
fireEvent,
6-
waitForElement,
7-
shallow,
8-
RenderAPI,
14+
render,
915
} from 'react-native-testing-library';
10-
import { ReactTestInstance } from 'react-test-renderer';
1116
import {
12-
ApplicationProvider,
13-
ApplicationProviderProps,
14-
} from '@kitten/theme';
17+
light,
18+
mapping,
19+
} from '@eva-design/eva';
20+
import { ApplicationProvider } from '../../theme';
1521
import {
1622
Radio,
17-
RadioComponent,
1823
RadioProps,
1924
} from './radio.component';
20-
import {
21-
mapping,
22-
theme,
23-
} from '../support/tests';
2425

25-
const Mock = (props?: RadioProps): React.ReactElement<ApplicationProviderProps> => {
26-
return (
26+
describe('@radio: component checks', () => {
27+
28+
const TestRadio = (props?: RadioProps) => (
2729
<ApplicationProvider
2830
mapping={mapping}
29-
theme={theme}>
31+
theme={light}>
3032
<Radio {...props} />
3133
</ApplicationProvider>
3234
);
33-
};
34-
35-
const renderComponent = (props?: RadioProps): RenderAPI => {
36-
return render(
37-
<Mock {...props}/>,
38-
);
39-
};
40-
41-
describe('@radio: matches snapshot', () => {
4235

43-
it('default', () => {
44-
const component: RenderAPI = renderComponent();
45-
const { output } = shallow(component.getByType(RadioComponent));
36+
it('should request checking', () => {
37+
const onCheckedChange = jest.fn();
4638

47-
expect(output).toMatchSnapshot();
48-
});
39+
const component = render(
40+
<TestRadio
41+
checked={false}
42+
onChange={onCheckedChange}
43+
/>,
44+
);
4945

50-
it('checked', () => {
51-
const component: RenderAPI = renderComponent({ checked: true });
52-
const { output } = shallow(component.getByType(Radio));
46+
fireEvent.press(component.getByType(TouchableOpacity));
5347

54-
expect(output).toMatchSnapshot();
48+
expect(onCheckedChange).toBeCalledWith(true);
5549
});
5650

57-
it('disabled', () => {
58-
const component: RenderAPI = renderComponent({ disabled: true });
59-
const { output } = shallow(component.getByType(Radio));
51+
it('should request unchecking', () => {
52+
const onCheckedChange = jest.fn();
6053

61-
expect(output).toMatchSnapshot();
62-
});
54+
const component = render(
55+
<TestRadio
56+
checked={true}
57+
onChange={onCheckedChange}
58+
/>,
59+
);
6360

64-
it('checked disabled', () => {
65-
const component: RenderAPI = renderComponent({
66-
checked: true,
67-
disabled: true,
68-
});
69-
const { output } = shallow(component.getByType(Radio));
61+
fireEvent.press(component.getByType(TouchableOpacity));
7062

71-
expect(output).toMatchSnapshot();
63+
expect(onCheckedChange).toBeCalledWith(false);
7264
});
7365

74-
it('active', async () => {
75-
const component: RenderAPI = renderComponent();
66+
it('should render text', () => {
67+
const component = render(
68+
<TestRadio text='I love Babel'/>,
69+
);
7670

77-
fireEvent(component.getByType(TouchableOpacity), 'pressIn');
78-
79-
const active: ReactTestInstance = await waitForElement(() => {
80-
return component.getByType(Radio);
81-
});
82-
const { output: activeOutput } = shallow(active);
83-
84-
fireEvent(component.getByType(TouchableOpacity), 'pressOut');
71+
const text = component.getByText('I love Babel');
8572

86-
const inactive: ReactTestInstance = await waitForElement(() => {
87-
return component.getByType(Radio);
88-
});
89-
const { output: inactiveOutput } = shallow(inactive);
90-
91-
expect(activeOutput).toMatchSnapshot();
92-
expect(inactiveOutput).toMatchSnapshot('default');
73+
expect(text).toBeTruthy();
9374
});
9475

95-
it('active checked', async () => {
96-
const component: RenderAPI = renderComponent({ checked: true });
76+
it('should render text as component', () => {
77+
const component = render(
78+
<TestRadio text={props => <Text {...props}>I love Babel</Text>}/>,
79+
);
9780

98-
fireEvent(component.getByType(TouchableOpacity), 'pressIn');
81+
const text = component.getByText('I love Babel');
9982

100-
const active: ReactTestInstance = await waitForElement(() => {
101-
return component.getByType(Radio);
102-
});
103-
const { output: activeOutput } = shallow(active);
83+
expect(text).toBeTruthy();
84+
});
10485

105-
fireEvent(component.getByType(TouchableOpacity), 'pressOut');
86+
it('should call onPressIn', () => {
87+
const onPressIn = jest.fn();
10688

107-
const inactive: ReactTestInstance = await waitForElement(() => {
108-
return component.getByType(Radio);
109-
});
110-
const { output: inactiveOutput } = shallow(inactive);
89+
const component = render(
90+
<TestRadio onPressIn={onPressIn}/>,
91+
);
11192

112-
expect(activeOutput).toMatchSnapshot();
113-
expect(inactiveOutput).toMatchSnapshot('checked');
114-
});
93+
fireEvent(component.getByType(TouchableOpacity), 'pressIn');
11594

116-
it('with text (styled)', () => {
117-
const component: RenderAPI = renderComponent({
118-
text: 'Place your text',
119-
textStyle: {
120-
fontSize: 22,
121-
lineHeight: 24,
122-
},
123-
});
124-
const { output } = shallow(component.getByType(Radio));
125-
126-
expect(output).toMatchSnapshot();
95+
expect(onPressIn).toBeCalled();
12796
});
12897

129-
});
130-
131-
describe('@radio: component checks', () => {
132-
133-
it('* emits onChange with correct args', () => {
134-
const onChange = jest.fn();
98+
it('should call onPressOut', () => {
99+
const onPressOut = jest.fn();
135100

136-
const component: RenderAPI = renderComponent({
137-
checked: false,
138-
onChange: onChange,
139-
});
101+
const component = render(
102+
<TestRadio onPressOut={onPressOut}/>,
103+
);
140104

141-
fireEvent.press(component.getByType(TouchableOpacity));
105+
fireEvent(component.getByType(TouchableOpacity), 'pressOut');
142106

143-
expect(onChange).toBeCalledWith(true);
107+
expect(onPressOut).toBeCalled();
144108
});
145109

146110
});

0 commit comments

Comments
 (0)