Files
react-native/IntegrationTests/LayoutEventsTest.js
T
Pieter Vanderwerff c940eb0c49 Add LTI annotations to function params in xplat/js [manually-modified]
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
2022-06-22 23:01:55 -07:00

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;