Skip to content

Commit edd7acb

Browse files
elicwhitefacebook-github-bot
authored andcommitted
ActivityIndicator ES6 Class
Reviewed By: yungsters Differential Revision: D8219463 fbshipit-source-id: 7d252d15bb4a7345d156b1659b09be2a4a69ba6c
1 parent a35a238 commit edd7acb

File tree

2 files changed

+96
-95
lines changed

2 files changed

+96
-95
lines changed

Libraries/Components/ActivityIndicator/ActivityIndicator.js

+80-94
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,15 @@
1010

1111
'use strict';
1212

13-
const ColorPropType = require('ColorPropType');
14-
const NativeMethodsMixin = require('NativeMethodsMixin');
1513
const Platform = require('Platform');
1614
const ProgressBarAndroid = require('ProgressBarAndroid');
17-
const PropTypes = require('prop-types');
1815
const React = require('React');
1916
const StyleSheet = require('StyleSheet');
2017
const View = require('View');
21-
const ViewPropTypes = require('ViewPropTypes');
2218

23-
const createReactClass = require('create-react-class');
2419
const requireNativeComponent = require('requireNativeComponent');
2520

21+
import type {NativeComponent} from 'ReactNative';
2622
import type {ViewProps} from 'ViewPropTypes';
2723

2824
let RCTActivityIndicator;
@@ -31,113 +27,103 @@ const GRAY = '#999999';
3127

3228
type IndicatorSize = number | 'small' | 'large';
3329

30+
type IOSProps = $ReadOnly<{|
31+
/**
32+
* Whether the indicator should hide when not animating (true by default).
33+
*
34+
* See http://facebook.github.io/react-native/docs/activityindicator.html#hideswhenstopped
35+
*/
36+
hidesWhenStopped?: ?boolean,
37+
|}>;
3438
type Props = $ReadOnly<{|
3539
...ViewProps,
40+
...IOSProps,
3641

42+
/**
43+
* Whether to show the indicator (true, the default) or hide it (false).
44+
*
45+
* See http://facebook.github.io/react-native/docs/activityindicator.html#animating
46+
*/
3747
animating?: ?boolean,
48+
49+
/**
50+
* The foreground color of the spinner (default is gray).
51+
*
52+
* See http://facebook.github.io/react-native/docs/activityindicator.html#color
53+
*/
3854
color?: ?string,
39-
hidesWhenStopped?: ?boolean,
55+
56+
/**
57+
* Size of the indicator (default is 'small').
58+
* Passing a number to the size prop is only supported on Android.
59+
*
60+
* See http://facebook.github.io/react-native/docs/activityindicator.html#size
61+
*/
4062
size?: ?IndicatorSize,
4163
|}>;
4264

43-
type DefaultProps = {
44-
animating: boolean,
45-
color: ?string,
46-
hidesWhenStopped: boolean,
47-
size: IndicatorSize,
48-
};
49-
5065
/**
5166
* Displays a circular loading indicator.
5267
*
5368
* See http://facebook.github.io/react-native/docs/activityindicator.html
5469
*/
55-
const ActivityIndicator = ((createReactClass({
56-
displayName: 'ActivityIndicator',
57-
mixins: [NativeMethodsMixin],
58-
59-
propTypes: {
60-
...ViewPropTypes,
61-
/**
62-
* Whether to show the indicator (true, the default) or hide it (false).
63-
*
64-
* See http://facebook.github.io/react-native/docs/activityindicator.html#animating
65-
*/
66-
animating: PropTypes.bool,
67-
/**
68-
* The foreground color of the spinner (default is gray).
69-
*
70-
* See http://facebook.github.io/react-native/docs/activityindicator.html#color
71-
*/
72-
color: ColorPropType,
73-
/**
74-
* Size of the indicator (default is 'small').
75-
* Passing a number to the size prop is only supported on Android.
76-
*
77-
* See http://facebook.github.io/react-native/docs/activityindicator.html#size
78-
*/
79-
size: PropTypes.oneOfType([
80-
PropTypes.oneOf(['small', 'large']),
81-
PropTypes.number,
82-
]),
83-
/**
84-
* Whether the indicator should hide when not animating (true by default).
85-
*
86-
* @platform ios
87-
*
88-
* See http://facebook.github.io/react-native/docs/activityindicator.html#hideswhenstopped
89-
*/
90-
hidesWhenStopped: PropTypes.bool,
91-
},
70+
const ActivityIndicator = (
71+
props: $ReadOnly<{|
72+
...Props,
73+
forwardedRef?: ?React.Ref<'RCTActivityIndicatorView'>,
74+
|}>,
75+
) => {
76+
const {onLayout, style, forwardedRef, ...restProps} = props;
77+
let sizeStyle;
78+
79+
switch (props.size) {
80+
case 'small':
81+
sizeStyle = styles.sizeSmall;
82+
break;
83+
case 'large':
84+
sizeStyle = styles.sizeLarge;
85+
break;
86+
default:
87+
sizeStyle = {height: props.size, width: props.size};
88+
break;
89+
}
90+
91+
const nativeProps = {
92+
...restProps,
93+
ref: forwardedRef,
94+
style: sizeStyle,
95+
styleAttr: 'Normal',
96+
indeterminate: true,
97+
};
98+
99+
return (
100+
<View onLayout={onLayout} style={[styles.container, style]}>
101+
{Platform.OS === 'ios' ? (
102+
<RCTActivityIndicator {...nativeProps} />
103+
) : (
104+
<ProgressBarAndroid {...nativeProps} />
105+
)}
106+
</View>
107+
);
108+
};
92109

93-
getDefaultProps(): DefaultProps {
94-
return {
95-
animating: true,
96-
color: Platform.OS === 'ios' ? GRAY : null,
97-
hidesWhenStopped: true,
98-
size: 'small',
99-
};
100-
},
110+
// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
111+
const ActivityIndicatorWithRef = React.forwardRef((props: Props, ref) => {
112+
return <ActivityIndicator {...props} forwardedRef={ref} />;
113+
});
101114

102-
render() {
103-
const {onLayout, style, ...props} = this.props;
104-
let sizeStyle;
105-
106-
switch (props.size) {
107-
case 'small':
108-
sizeStyle = styles.sizeSmall;
109-
break;
110-
case 'large':
111-
sizeStyle = styles.sizeLarge;
112-
break;
113-
default:
114-
sizeStyle = {height: props.size, width: props.size};
115-
break;
116-
}
117-
118-
const nativeProps = {
119-
...props,
120-
style: sizeStyle,
121-
styleAttr: 'Normal',
122-
indeterminate: true,
123-
};
124-
125-
return (
126-
<View onLayout={onLayout} style={[styles.container, style]}>
127-
{Platform.OS === 'ios' ? (
128-
<RCTActivityIndicator {...nativeProps} />
129-
) : (
130-
<ProgressBarAndroid {...nativeProps} />
131-
)}
132-
</View>
133-
);
134-
},
135-
}): any): React.ComponentType<Props>);
115+
ActivityIndicatorWithRef.defaultProps = {
116+
animating: true,
117+
color: Platform.OS === 'ios' ? GRAY : null,
118+
hidesWhenStopped: true,
119+
size: 'small',
120+
};
121+
ActivityIndicatorWithRef.displayName = 'ActivityIndicator';
136122

137123
if (Platform.OS === 'ios') {
138124
RCTActivityIndicator = requireNativeComponent(
139125
'RCTActivityIndicatorView',
140-
ActivityIndicator,
126+
null,
141127
{nativeOnly: {activityIndicatorViewStyle: true}},
142128
);
143129
}
@@ -157,4 +143,4 @@ const styles = StyleSheet.create({
157143
},
158144
});
159145

160-
module.exports = ActivityIndicator;
146+
module.exports = (ActivityIndicatorWithRef: Class<NativeComponent<Props>>);

jest/mockComponent.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,24 @@ module.exports = (moduleName, instanceMethods) => {
2020
render() {
2121
const name = RealComponent.displayName || RealComponent.name;
2222

23+
const props = Object.assign({}, RealComponent.defaultProps);
24+
25+
if (this.props) {
26+
Object.keys(this.props).forEach(prop => {
27+
// We can't just assign props on top of defaultProps
28+
// because React treats undefined as special and different from null.
29+
// If a prop is specified but set to undefined it is ignored and the
30+
// default prop is used instead. If it is set to null, then the
31+
// null value overwrites the default value.
32+
if (this.props[prop] !== undefined) {
33+
props[prop] = this.props[prop];
34+
}
35+
});
36+
}
37+
2338
return React.createElement(
2439
name.replace(/^(RCT|RK)/, ''),
25-
this.props,
40+
props,
2641
this.props.children,
2742
);
2843
}

0 commit comments

Comments
 (0)