mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
c940eb0c49
Summary: Add annotations to function parameters required for Flow's Local Type Inference project. This codemod prepares the codebase to match Flow's new typechecking algorithm. The new algorithm will make Flow more reliable and predicatable. Reviewed By: bradzacher Differential Revision: D37363351 fbshipit-source-id: a9d3df7db6f9d094ac2ce81aae1f3ab4f62b243a
205 lines
5.4 KiB
JavaScript
205 lines
5.4 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
* @flow strict-local
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const React = require('react');
|
|
const ReactNative = require('react-native');
|
|
const {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative;
|
|
const {TestModule} = ReactNative.NativeModules;
|
|
|
|
import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
|
|
|
|
const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer');
|
|
|
|
function debug(...args: Array<void | Layout | string>) {
|
|
// console.log.apply(null, arguments);
|
|
}
|
|
|
|
import type {
|
|
Layout,
|
|
LayoutEvent,
|
|
} from 'react-native/Libraries/Types/CoreEventTypes';
|
|
|
|
type Props = $ReadOnly<{||}>;
|
|
|
|
type State = {
|
|
didAnimation: boolean,
|
|
extraText?: string,
|
|
imageLayout?: Layout,
|
|
textLayout?: Layout,
|
|
viewLayout?: Layout,
|
|
viewStyle?: ViewStyleProp,
|
|
containerStyle?: ViewStyleProp,
|
|
...
|
|
};
|
|
|
|
class LayoutEventsTest extends React.Component<Props, State> {
|
|
_view: ?React.ElementRef<typeof View>;
|
|
_img: ?React.ElementRef<typeof Image>;
|
|
_txt: ?React.ElementRef<typeof Text>;
|
|
|
|
state: State = {
|
|
didAnimation: false,
|
|
};
|
|
|
|
animateViewLayout() {
|
|
debug('animateViewLayout invoked');
|
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring, () => {
|
|
debug('animateViewLayout done');
|
|
this.checkLayout(this.addWrapText);
|
|
});
|
|
this.setState({viewStyle: {margin: 60}});
|
|
}
|
|
|
|
addWrapText: () => void = () => {
|
|
debug('addWrapText invoked');
|
|
this.setState(
|
|
{extraText: ' And a bunch more text to wrap around a few lines.'},
|
|
() => this.checkLayout(this.changeContainer),
|
|
);
|
|
};
|
|
|
|
changeContainer: () => void = () => {
|
|
debug('changeContainer invoked');
|
|
this.setState({containerStyle: {width: 280}}, () =>
|
|
this.checkLayout(TestModule.markTestCompleted),
|
|
);
|
|
};
|
|
|
|
checkLayout: (next?: ?() => void) => void = (next?: ?() => void) => {
|
|
const view = this._view;
|
|
const txt = this._txt;
|
|
const img = this._img;
|
|
|
|
if (view == null || txt == null || img == null) {
|
|
return;
|
|
}
|
|
|
|
view.measure((x, y, width, height) => {
|
|
this.compare(
|
|
'view',
|
|
{x, y, width, height},
|
|
this.state.viewLayout || null,
|
|
);
|
|
if (typeof next === 'function') {
|
|
next();
|
|
} else if (!this.state.didAnimation) {
|
|
// Trigger first state change after onLayout fires
|
|
this.animateViewLayout();
|
|
this.state.didAnimation = true;
|
|
}
|
|
});
|
|
|
|
txt.measure((x, y, width, height) => {
|
|
this.compare('txt', {x, y, width, height}, this.state.textLayout);
|
|
});
|
|
|
|
img.measure((x, y, width, height) => {
|
|
this.compare('img', {x, y, width, height}, this.state.imageLayout);
|
|
});
|
|
};
|
|
|
|
compare(node: string, measured: Layout, onLayout?: ?Layout): void {
|
|
if (deepDiffer(measured, onLayout)) {
|
|
const data = {measured, onLayout};
|
|
throw new Error(
|
|
node +
|
|
' onLayout mismatch with measure ' +
|
|
JSON.stringify(data, null, ' '),
|
|
);
|
|
}
|
|
}
|
|
|
|
onViewLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => {
|
|
// $FlowFixMe[incompatible-call]
|
|
debug('received view layout event\n', e.nativeEvent);
|
|
this.setState({viewLayout: e.nativeEvent.layout}, this.checkLayout);
|
|
};
|
|
|
|
onTextLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => {
|
|
// $FlowFixMe[incompatible-call]
|
|
debug('received text layout event\n', e.nativeEvent);
|
|
this.setState({textLayout: e.nativeEvent.layout}, this.checkLayout);
|
|
};
|
|
|
|
onImageLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => {
|
|
// $FlowFixMe[incompatible-call]
|
|
debug('received image layout event\n', e.nativeEvent);
|
|
this.setState({imageLayout: e.nativeEvent.layout}, this.checkLayout);
|
|
};
|
|
|
|
render(): React.Node {
|
|
const viewStyle = [styles.view, this.state.viewStyle];
|
|
const textLayout = this.state.textLayout || {width: '?', height: '?'};
|
|
const imageLayout = this.state.imageLayout || {x: '?', y: '?'};
|
|
debug('viewLayout', this.state.viewLayout);
|
|
return (
|
|
<View style={[styles.container, this.state.containerStyle]}>
|
|
<View
|
|
ref={ref => {
|
|
this._view = ref;
|
|
}}
|
|
onLayout={this.onViewLayout}
|
|
style={viewStyle}>
|
|
<Image
|
|
ref={ref => {
|
|
this._img = ref;
|
|
}}
|
|
onLayout={this.onImageLayout}
|
|
style={styles.image}
|
|
source={{uri: 'uie_thumb_big.png'}}
|
|
/>
|
|
<Text
|
|
ref={ref => {
|
|
this._txt = ref;
|
|
}}
|
|
onLayout={this.onTextLayout}
|
|
style={styles.text}>
|
|
A simple piece of text.{this.state.extraText}
|
|
</Text>
|
|
<Text>
|
|
{'\n'}
|
|
Text w/h: {textLayout.width}/{textLayout.height + '\n'}
|
|
Image x/y: {imageLayout.x}/{imageLayout.y}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
margin: 40,
|
|
},
|
|
view: {
|
|
margin: 20,
|
|
padding: 12,
|
|
borderColor: 'black',
|
|
borderWidth: 0.5,
|
|
backgroundColor: 'transparent',
|
|
},
|
|
text: {
|
|
alignSelf: 'flex-start',
|
|
borderColor: 'rgba(0, 0, 255, 0.2)',
|
|
borderWidth: 0.5,
|
|
},
|
|
image: {
|
|
width: 50,
|
|
height: 50,
|
|
marginBottom: 10,
|
|
alignSelf: 'center',
|
|
},
|
|
});
|
|
|
|
LayoutEventsTest.displayName = 'LayoutEventsTest';
|
|
module.exports = LayoutEventsTest;
|