Skip to content

Commit b963158

Browse files
Julian Hundelohsatya164
Julian Hundeloh
authored andcommitted
feat: export platform dependent CheckBox and RadioButton
1 parent 1e3ddc4 commit b963158

File tree

6 files changed

+422
-252
lines changed

6 files changed

+422
-252
lines changed

src/components/Checkbox.js

+12-105
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
/* @flow */
22

33
import * as React from 'react';
4-
import { Animated, View, Platform, StyleSheet } from 'react-native';
5-
import color from 'color';
6-
import Icon from './Icon';
7-
import TouchableRipple from './TouchableRipple';
4+
import { Platform } from 'react-native';
5+
import CheckboxAndroid from './CheckboxAndroid';
6+
import CheckboxIOS from './CheckboxIOS';
87
import withTheme from '../core/withTheme';
98
import type { Theme } from '../types';
109

@@ -35,10 +34,6 @@ type Props = {
3534
theme: Theme,
3635
};
3736

38-
type State = {
39-
scaleAnim: Animated.Value,
40-
};
41-
4237
/**
4338
* Checkboxes allow the selection of multiple options from a set.
4439
*
@@ -83,108 +78,20 @@ type State = {
8378
* }
8479
* ```
8580
*/
86-
class Checkbox extends React.Component<Props, State> {
87-
state = {
88-
scaleAnim: new Animated.Value(1),
89-
};
81+
class Checkbox extends React.Component<Props> {
82+
// @component ./CheckboxAndroid.js
83+
static Android = CheckboxAndroid;
9084

91-
componentDidUpdate(prevProps) {
92-
if (prevProps.checked === this.props.checked || Platform.OS !== 'android') {
93-
return;
94-
}
95-
96-
Animated.sequence([
97-
Animated.timing(this.state.scaleAnim, {
98-
toValue: 0.85,
99-
duration: this.props.checked ? 200 : 0,
100-
}),
101-
Animated.timing(this.state.scaleAnim, {
102-
toValue: 1,
103-
duration: this.props.checked ? 200 : 350,
104-
}),
105-
]).start();
106-
}
85+
// @component ./CheckboxIOS.js
86+
static IOS = CheckboxIOS;
10787

10888
render() {
109-
const { checked, disabled, onPress, theme, ...rest } = this.props;
110-
const checkedColor = this.props.color || theme.colors.accent;
111-
const uncheckedColor =
112-
this.props.uncheckedColor ||
113-
color(theme.colors.text)
114-
.alpha(theme.dark ? 0.7 : 0.54)
115-
.rgb()
116-
.string();
117-
118-
let rippleColor, checkboxColor;
119-
120-
if (disabled) {
121-
rippleColor = color(theme.colors.text)
122-
.alpha(0.16)
123-
.rgb()
124-
.string();
125-
checkboxColor = theme.colors.disabled;
126-
} else {
127-
rippleColor = color(checkedColor)
128-
.fade(0.32)
129-
.rgb()
130-
.string();
131-
checkboxColor = checked ? checkedColor : uncheckedColor;
132-
}
133-
134-
const borderWidth = this.state.scaleAnim.interpolate({
135-
inputRange: [0.8, 1],
136-
outputRange: [7, 0],
137-
});
138-
139-
return (
140-
<TouchableRipple
141-
{...rest}
142-
borderless
143-
rippleColor={rippleColor}
144-
onPress={onPress}
145-
disabled={disabled}
146-
accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'}
147-
accessibilityComponentType="button"
148-
accessibilityLiveRegion="polite"
149-
style={styles.container}
150-
>
151-
<Animated.View style={{ transform: [{ scale: this.state.scaleAnim }] }}>
152-
<Icon
153-
allowFontScaling={false}
154-
source={checked ? 'check-box' : 'check-box-outline-blank'}
155-
size={24}
156-
color={checkboxColor}
157-
/>
158-
<View style={[StyleSheet.absoluteFill, styles.fillContainer]}>
159-
<Animated.View
160-
style={[
161-
styles.fill,
162-
{ borderColor: checkboxColor },
163-
{ borderWidth },
164-
]}
165-
/>
166-
</View>
167-
</Animated.View>
168-
</TouchableRipple>
89+
return Platform.OS === 'ios' ? (
90+
<CheckboxIOS {...this.props} />
91+
) : (
92+
<CheckboxAndroid {...this.props} />
16993
);
17094
}
17195
}
17296

173-
const styles = StyleSheet.create({
174-
container: {
175-
borderRadius: 18,
176-
width: 36,
177-
height: 36,
178-
padding: 6,
179-
},
180-
fillContainer: {
181-
alignItems: 'center',
182-
justifyContent: 'center',
183-
},
184-
fill: {
185-
height: 14,
186-
width: 14,
187-
},
188-
});
189-
19097
export default withTheme(Checkbox);

src/components/CheckboxAndroid.js

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/* @flow */
2+
3+
import * as React from 'react';
4+
import { Animated, View, StyleSheet } from 'react-native';
5+
import color from 'color';
6+
import Icon from './Icon';
7+
import TouchableRipple from './TouchableRipple';
8+
import withTheme from '../core/withTheme';
9+
import type { Theme } from '../types';
10+
11+
type Props = {
12+
/**
13+
* Whether checkbox is checked.
14+
*/
15+
checked: boolean,
16+
/**
17+
* Whether checkbox is disabled.
18+
*/
19+
disabled?: boolean,
20+
/**
21+
* Function to execute on press.
22+
*/
23+
onPress?: () => mixed,
24+
/**
25+
* Custom color for unchecked checkbox.
26+
*/
27+
uncheckedColor?: string,
28+
/**
29+
* Custom color for checkbox.
30+
*/
31+
color?: string,
32+
/**
33+
* @optional
34+
*/
35+
theme: Theme,
36+
};
37+
38+
type State = {
39+
scaleAnim: Animated.Value,
40+
};
41+
42+
/**
43+
* Checkboxes allow the selection of multiple options from a set.
44+
* This component follows platform guidelines for Android.
45+
*
46+
* <div class="screenshots">
47+
* <figure>
48+
* <img src="screenshots/checkbox-enabled.android.png" />
49+
* <figcaption>Enabled</figcaption>
50+
* </figure>
51+
* <figure>
52+
* <img src="screenshots/checkbox-disabled.android.png" />
53+
* <figcaption>Disabled</figcaption>
54+
* </figure>
55+
* </div>
56+
*/
57+
class CheckboxAndroid extends React.Component<Props, State> {
58+
static displayName = 'Checkbox.Android';
59+
60+
state = {
61+
scaleAnim: new Animated.Value(1),
62+
};
63+
64+
componentDidUpdate(prevProps) {
65+
if (prevProps.checked === this.props.checked) {
66+
return;
67+
}
68+
69+
Animated.sequence([
70+
Animated.timing(this.state.scaleAnim, {
71+
toValue: 0.85,
72+
duration: this.props.checked ? 200 : 0,
73+
}),
74+
Animated.timing(this.state.scaleAnim, {
75+
toValue: 1,
76+
duration: this.props.checked ? 200 : 350,
77+
}),
78+
]).start();
79+
}
80+
81+
render() {
82+
const { checked, disabled, onPress, theme, ...rest } = this.props;
83+
const checkedColor = this.props.color || theme.colors.accent;
84+
const uncheckedColor =
85+
this.props.uncheckedColor ||
86+
color(theme.colors.text)
87+
.alpha(theme.dark ? 0.7 : 0.54)
88+
.rgb()
89+
.string();
90+
91+
let rippleColor, checkboxColor;
92+
93+
if (disabled) {
94+
rippleColor = color(theme.colors.text)
95+
.alpha(0.16)
96+
.rgb()
97+
.string();
98+
checkboxColor = theme.colors.disabled;
99+
} else {
100+
rippleColor = color(checkedColor)
101+
.fade(0.32)
102+
.rgb()
103+
.string();
104+
checkboxColor = checked ? checkedColor : uncheckedColor;
105+
}
106+
107+
const borderWidth = this.state.scaleAnim.interpolate({
108+
inputRange: [0.8, 1],
109+
outputRange: [7, 0],
110+
});
111+
112+
return (
113+
<TouchableRipple
114+
{...rest}
115+
borderless
116+
rippleColor={rippleColor}
117+
onPress={onPress}
118+
disabled={disabled}
119+
accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'}
120+
accessibilityComponentType="button"
121+
accessibilityLiveRegion="polite"
122+
style={styles.container}
123+
>
124+
<Animated.View style={{ transform: [{ scale: this.state.scaleAnim }] }}>
125+
<Icon
126+
allowFontScaling={false}
127+
source={checked ? 'check-box' : 'check-box-outline-blank'}
128+
size={24}
129+
color={checkboxColor}
130+
/>
131+
<View style={[StyleSheet.absoluteFill, styles.fillContainer]}>
132+
<Animated.View
133+
style={[
134+
styles.fill,
135+
{ borderColor: checkboxColor },
136+
{ borderWidth },
137+
]}
138+
/>
139+
</View>
140+
</Animated.View>
141+
</TouchableRipple>
142+
);
143+
}
144+
}
145+
146+
const styles = StyleSheet.create({
147+
container: {
148+
borderRadius: 18,
149+
width: 36,
150+
height: 36,
151+
padding: 6,
152+
},
153+
fillContainer: {
154+
alignItems: 'center',
155+
justifyContent: 'center',
156+
},
157+
fill: {
158+
height: 14,
159+
width: 14,
160+
},
161+
});
162+
163+
export default withTheme(CheckboxAndroid);

src/components/Checkbox.ios.js renamed to src/components/CheckboxIOS.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,22 @@ type Props = {
3333

3434
/**
3535
* Checkboxes allow the selection of multiple options from a set.
36+
* This component follows platform guidelines for iOS.
37+
*
38+
* <div class="screenshots">
39+
* <figure>
40+
* <img src="screenshots/checkbox-enabled.ios.png" />
41+
* <figcaption>Enabled</figcaption>
42+
* </figure>
43+
* <figure>
44+
* <img src="screenshots/checkbox-disabled.ios.png" />
45+
* <figcaption>Disabled</figcaption>
46+
* </figure>
47+
* </div>
3648
*/
37-
class Checkbox extends React.Component<Props> {
49+
class CheckboxIOS extends React.Component<Props> {
50+
static displayName = 'Checkbox.IOS';
51+
3852
render() {
3953
const { checked, disabled, onPress, theme, ...rest } = this.props;
4054

@@ -88,4 +102,4 @@ const styles = StyleSheet.create({
88102
},
89103
});
90104

91-
export default withTheme(Checkbox);
105+
export default withTheme(CheckboxIOS);

0 commit comments

Comments
 (0)