Merge branch 'master' into 0.58-stable

This commit is contained in:
Mike Grabowski 2018-11-22 17:33:25 +01:00
Родитель a525941ab6 8f283b93ea
Коммит 696bd89013
135 изменённых файлов: 2522 добавлений и 1214 удалений

Просмотреть файл

@ -101,4 +101,4 @@ untyped-import
untyped-type-import
[version]
^0.85.0
^0.86.0

Просмотреть файл

@ -101,4 +101,4 @@ untyped-import
untyped-type-import
[version]
^0.85.0
^0.86.0

Просмотреть файл

@ -349,9 +349,6 @@ class AnimatedInterpolation extends AnimatedWithChildren {
__transformDataType(range: Array<any>) {
// Change the string array type to number array
// So we can reuse the same logic in iOS and Android platform
/* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.70 was deployed. To see the error delete this
* comment and run Flow. */
return range.map(function(value) {
if (typeof value !== 'string') {
return value;

Просмотреть файл

@ -16,6 +16,16 @@
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
@interface RCTImagePickerController : UIImagePickerController
@property (nonatomic, assign) BOOL unmirrorFrontFacingCamera;
@end
@implementation RCTImagePickerController
@end
@interface RCTImagePickerManager () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@end
@ -31,6 +41,22 @@ RCT_EXPORT_MODULE(ImagePickerIOS);
@synthesize bridge = _bridge;
- (id)init
{
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(cameraChanged:)
name:@"AVCaptureDeviceDidStartRunningNotification"
object:nil];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVCaptureDeviceDidStartRunningNotification" object:nil];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
@ -56,9 +82,10 @@ RCT_EXPORT_METHOD(openCameraDialog:(NSDictionary *)config
return;
}
UIImagePickerController *imagePicker = [UIImagePickerController new];
RCTImagePickerController *imagePicker = [RCTImagePickerController new];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.unmirrorFrontFacingCamera = [RCTConvert BOOL:config[@"unmirrorFrontFacingCamera"]];
if ([RCTConvert BOOL:config[@"videoMode"]]) {
imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
@ -175,4 +202,17 @@ didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
}
}
- (void)cameraChanged:(NSNotification *)notification
{
for (UIImagePickerController *picker in _pickers) {
if ([picker isKindOfClass:[RCTImagePickerController class]]
&& ((RCTImagePickerController *)picker).unmirrorFrontFacingCamera
&& picker.cameraDevice == UIImagePickerControllerCameraDeviceFront) {
picker.cameraViewTransform = CGAffineTransformScale(CGAffineTransformIdentity, -1, 1);
} else {
picker.cameraViewTransform = CGAffineTransformIdentity;
}
}
}
@end

Просмотреть файл

@ -14,27 +14,42 @@ export type TVParallaxPropertiesType = $ReadOnly<{|
/**
* If true, parallax effects are enabled. Defaults to true.
*/
enabled: boolean,
enabled?: boolean,
/**
* Defaults to 2.0.
*/
shiftDistanceX: number,
shiftDistanceX?: number,
/**
* Defaults to 2.0.
*/
shiftDistanceY: number,
shiftDistanceY?: number,
/**
* Defaults to 0.05.
*/
tiltAngle: number,
tiltAngle?: number,
/**
* Defaults to 1.0
*/
magnification: number,
magnification?: number,
/**
* Defaults to 1.0
*/
pressMagnification?: number,
/**
* Defaults to 0.3
*/
pressDuration?: number,
/**
* Defaults to 0.3
*/
pressDelay?: number,
|}>;
/**

Просмотреть файл

@ -4,35 +4,150 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const DeprecatedColorPropType = require('DeprecatedColorPropType');
const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
const NativeMethodsMixin = require('NativeMethodsMixin');
const Platform = require('Platform');
const PropTypes = require('prop-types');
const React = require('React');
const ReactNative = require('ReactNative');
const StatusBar = require('StatusBar');
const StyleSheet = require('StyleSheet');
const UIManager = require('UIManager');
const View = require('View');
const nullthrows = require('nullthrows');
const DrawerConsts = UIManager.getViewManagerConfig('AndroidDrawerLayout')
.Constants;
const createReactClass = require('create-react-class');
const dismissKeyboard = require('dismissKeyboard');
const requireNativeComponent = require('requireNativeComponent');
const RK_DRAWER_REF = 'drawerlayout';
const INNERVIEW_REF = 'innerView';
const DRAWER_STATES = ['Idle', 'Dragging', 'Settling'];
import type {ViewStyleProp} from 'StyleSheet';
import type {ColorValue} from 'StyleSheetTypes';
import type {SyntheticEvent} from 'CoreEventTypes';
import type {
MeasureOnSuccessCallback,
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
} from 'ReactNativeTypes';
type DrawerStates = 'Idle' | 'Dragging' | 'Settling';
type DrawerStateEvent = SyntheticEvent<
$ReadOnly<{|
drawerState: number,
|}>,
>;
type DrawerSlideEvent = SyntheticEvent<
$ReadOnly<{|
offset: number,
|}>,
>;
type Props = $ReadOnly<{|
/**
* Determines whether the keyboard gets dismissed in response to a drag.
* - 'none' (the default), drags do not dismiss the keyboard.
* - 'on-drag', the keyboard is dismissed when a drag begins.
*/
keyboardDismissMode?: ?('none' | 'on-drag'),
/**
* Specifies the background color of the drawer. The default value is white.
* If you want to set the opacity of the drawer, use rgba. Example:
*
* ```
* return (
* <DrawerLayoutAndroid drawerBackgroundColor="rgba(0,0,0,0.5)">
* </DrawerLayoutAndroid>
* );
* ```
*/
drawerBackgroundColor: ColorValue,
/**
* Specifies the side of the screen from which the drawer will slide in.
*/
drawerPosition: ?number,
/**
* Specifies the width of the drawer, more precisely the width of the view that be pulled in
* from the edge of the window.
*/
drawerWidth?: ?number,
/**
* Specifies the lock mode of the drawer. The drawer can be locked in 3 states:
* - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures.
* - locked-closed, meaning that the drawer will stay closed and not respond to gestures.
* - locked-open, meaning that the drawer will stay opened and not respond to gestures.
* The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`).
*/
drawerLockMode?: ?('unlocked' | 'locked-closed' | 'locked-open'),
/**
* Function called whenever there is an interaction with the navigation view.
*/
onDrawerSlide?: ?(event: DrawerSlideEvent) => mixed,
/**
* Function called when the drawer state has changed. The drawer can be in 3 states:
* - Idle, meaning there is no interaction with the navigation view happening at the time
* - Dragging, meaning there is currently an interaction with the navigation view
* - Settling, meaning that there was an interaction with the navigation view, and the
* navigation view is now finishing its closing or opening animation
*/
onDrawerStateChanged?: ?(state: DrawerStates) => mixed,
/**
* Function called whenever the navigation view has been opened.
*/
onDrawerOpen?: ?() => mixed,
/**
* Function called whenever the navigation view has been closed.
*/
onDrawerClose?: ?() => mixed,
/**
* The navigation view that will be rendered to the side of the screen and can be pulled in.
*/
renderNavigationView: () => React.Element<any>,
/**
* Make the drawer take the entire screen and draw the background of the
* status bar to allow it to open over the status bar. It will only have an
* effect on API 21+.
*/
statusBarBackgroundColor?: ?ColorValue,
children?: React.Node,
style?: ?ViewStyleProp,
|}>;
type NativeProps = $ReadOnly<{|
...$Diff<
Props,
$ReadOnly<{onDrawerStateChanged?: ?(state: DrawerStates) => mixed}>,
>,
onDrawerStateChanged?: ?(state: DrawerStateEvent) => mixed,
|}>;
type State = {|
statusBarBackgroundColor: ColorValue,
|};
// The View that contains both the actual drawer and the main view
const AndroidDrawerLayout = ((requireNativeComponent(
'AndroidDrawerLayout',
): any): Class<ReactNative.NativeComponent<NativeProps>>);
/**
* React component that wraps the platform `DrawerLayout` (Android only). The
* Drawer (typically used for navigation) is rendered with `renderNavigationView`
@ -64,109 +179,20 @@ const DRAWER_STATES = ['Idle', 'Dragging', 'Settling'];
* },
* ```
*/
const DrawerLayoutAndroid = createReactClass({
displayName: 'DrawerLayoutAndroid',
statics: {
positions: DrawerConsts.DrawerPosition,
},
class DrawerLayoutAndroid extends React.Component<Props, State> {
static positions = DrawerConsts.DrawerPosition;
static defaultProps = {
drawerBackgroundColor: 'white',
};
propTypes: {
...DeprecatedViewPropTypes,
/**
* Determines whether the keyboard gets dismissed in response to a drag.
* - 'none' (the default), drags do not dismiss the keyboard.
* - 'on-drag', the keyboard is dismissed when a drag begins.
*/
keyboardDismissMode: PropTypes.oneOf([
'none', // default
'on-drag',
]),
/**
* Specifies the background color of the drawer. The default value is white.
* If you want to set the opacity of the drawer, use rgba. Example:
*
* ```
* return (
* <DrawerLayoutAndroid drawerBackgroundColor="rgba(0,0,0,0.5)">
* </DrawerLayoutAndroid>
* );
* ```
*/
drawerBackgroundColor: DeprecatedColorPropType,
/**
* Specifies the side of the screen from which the drawer will slide in.
*/
drawerPosition: PropTypes.oneOf([
DrawerConsts.DrawerPosition.Left,
DrawerConsts.DrawerPosition.Right,
]),
/**
* Specifies the width of the drawer, more precisely the width of the view that be pulled in
* from the edge of the window.
*/
drawerWidth: PropTypes.number,
/**
* Specifies the lock mode of the drawer. The drawer can be locked in 3 states:
* - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures.
* - locked-closed, meaning that the drawer will stay closed and not respond to gestures.
* - locked-open, meaning that the drawer will stay opened and not respond to gestures.
* The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`).
*/
drawerLockMode: PropTypes.oneOf([
'unlocked',
'locked-closed',
'locked-open',
]),
/**
* Function called whenever there is an interaction with the navigation view.
*/
onDrawerSlide: PropTypes.func,
/**
* Function called when the drawer state has changed. The drawer can be in 3 states:
* - idle, meaning there is no interaction with the navigation view happening at the time
* - dragging, meaning there is currently an interaction with the navigation view
* - settling, meaning that there was an interaction with the navigation view, and the
* navigation view is now finishing its closing or opening animation
*/
onDrawerStateChanged: PropTypes.func,
/**
* Function called whenever the navigation view has been opened.
*/
onDrawerOpen: PropTypes.func,
/**
* Function called whenever the navigation view has been closed.
*/
onDrawerClose: PropTypes.func,
/**
* The navigation view that will be rendered to the side of the screen and can be pulled in.
*/
renderNavigationView: PropTypes.func.isRequired,
_nativeRef = React.createRef<
Class<ReactNative.NativeComponent<NativeProps>>,
>();
/**
* Make the drawer take the entire screen and draw the background of the
* status bar to allow it to open over the status bar. It will only have an
* effect on API 21+.
*/
statusBarBackgroundColor: DeprecatedColorPropType,
},
state = {statusBarBackgroundColor: null};
mixins: [NativeMethodsMixin],
getDefaultProps: function(): {drawerBackgroundColor: string} {
return {
drawerBackgroundColor: 'white',
};
},
getInitialState: function() {
return {statusBarBackgroundColor: undefined};
},
getInnerViewNode: function() {
return this.refs[INNERVIEW_REF].getInnerViewNode();
},
render: function() {
render() {
const {onDrawerStateChanged, ...props} = this.props;
const drawStatusBar =
Platform.Version >= 21 && this.props.statusBarBackgroundColor;
const drawerViewWrapper = (
@ -184,7 +210,7 @@ const DrawerLayoutAndroid = createReactClass({
</View>
);
const childrenWrapper = (
<View ref={INNERVIEW_REF} style={styles.mainSubview} collapsable={false}>
<View style={styles.mainSubview} collapsable={false}>
{drawStatusBar && (
<StatusBar
translucent
@ -204,8 +230,8 @@ const DrawerLayoutAndroid = createReactClass({
);
return (
<AndroidDrawerLayout
{...this.props}
ref={RK_DRAWER_REF}
{...props}
ref={this._nativeRef}
drawerWidth={this.props.drawerWidth}
drawerPosition={this.props.drawerPosition}
drawerLockMode={this.props.drawerLockMode}
@ -218,59 +244,60 @@ const DrawerLayoutAndroid = createReactClass({
{drawerViewWrapper}
</AndroidDrawerLayout>
);
},
}
_onDrawerSlide: function(event) {
_onDrawerSlide = (event: DrawerSlideEvent) => {
if (this.props.onDrawerSlide) {
this.props.onDrawerSlide(event);
}
if (this.props.keyboardDismissMode === 'on-drag') {
dismissKeyboard();
}
},
};
_onDrawerOpen: function() {
_onDrawerOpen = () => {
if (this.props.onDrawerOpen) {
this.props.onDrawerOpen();
}
},
};
_onDrawerClose: function() {
_onDrawerClose = () => {
if (this.props.onDrawerClose) {
this.props.onDrawerClose();
}
},
};
_onDrawerStateChanged: function(event) {
_onDrawerStateChanged = (event: DrawerStateEvent) => {
if (this.props.onDrawerStateChanged) {
this.props.onDrawerStateChanged(
DRAWER_STATES[event.nativeEvent.drawerState],
);
}
},
};
/**
* Opens the drawer.
*/
openDrawer: function() {
openDrawer() {
UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(),
UIManager.getViewManagerConfig('AndroidDrawerLayout').Commands.openDrawer,
null,
);
},
}
/**
* Closes the drawer.
*/
closeDrawer: function() {
closeDrawer() {
UIManager.dispatchViewManagerCommand(
this._getDrawerLayoutHandle(),
UIManager.getViewManagerConfig('AndroidDrawerLayout').Commands
.closeDrawer,
null,
);
},
}
/**
* Closing and opening example
* Note: To access the drawer you have to give it a ref. Refs do not work on stateless components
@ -287,10 +314,45 @@ const DrawerLayoutAndroid = createReactClass({
* )
* }
*/
_getDrawerLayoutHandle: function() {
return ReactNative.findNodeHandle(this.refs[RK_DRAWER_REF]);
},
});
_getDrawerLayoutHandle() {
return ReactNative.findNodeHandle(this._nativeRef.current);
}
/**
* Native methods
*/
blur() {
nullthrows(this._nativeRef.current).blur();
}
focus() {
nullthrows(this._nativeRef.current).focus();
}
measure(callback: MeasureOnSuccessCallback) {
nullthrows(this._nativeRef.current).measure(callback);
}
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
nullthrows(this._nativeRef.current).measureInWindow(callback);
}
measureLayout(
relativeToNativeNode: number,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void,
) {
nullthrows(this._nativeRef.current).measureLayout(
relativeToNativeNode,
onSuccess,
onFail,
);
}
setNativeProps(nativeProps: Object) {
nullthrows(this._nativeRef.current).setNativeProps(nativeProps);
}
}
const styles = StyleSheet.create({
base: {
@ -322,7 +384,4 @@ const styles = StyleSheet.create({
},
});
// The View that contains both the actual drawer and the main view
const AndroidDrawerLayout = requireNativeComponent('AndroidDrawerLayout');
module.exports = DrawerLayoutAndroid;

Просмотреть файл

@ -24,6 +24,8 @@ const warning = require('fbjs/lib/warning');
const {ScrollViewManager} = require('NativeModules');
import type {PressEvent, ScrollEvent} from 'CoreEventTypes';
import type {KeyboardEvent} from 'Keyboard';
import type EmitterSubscription from 'EmitterSubscription';
/**
@ -113,7 +115,6 @@ type State = {
observedScrollSinceBecomingResponder: boolean,
becameResponderWhileAnimating: boolean,
};
type Event = Object;
const ScrollResponderMixin = {
_subscriptionKeyboardWillShow: (null: ?EmitterSubscription),
@ -168,7 +169,9 @@ const ScrollResponderMixin = {
* true.
*
*/
scrollResponderHandleStartShouldSetResponder: function(e: Event): boolean {
scrollResponderHandleStartShouldSetResponder: function(
e: PressEvent,
): boolean {
const currentlyFocusedTextInput = TextInputState.currentlyFocusedField();
if (
@ -193,7 +196,7 @@ const ScrollResponderMixin = {
* Invoke this from an `onStartShouldSetResponderCapture` event.
*/
scrollResponderHandleStartShouldSetResponderCapture: function(
e: Event,
e: PressEvent,
): boolean {
// The scroll view should receive taps instead of its descendants if:
// * it is already animating/decelerating
@ -212,6 +215,7 @@ const ScrollResponderMixin = {
if (
keyboardNeverPersistTaps &&
currentlyFocusedTextInput != null &&
e.target &&
!TextInputState.isTextInput(e.target)
) {
return true;
@ -254,9 +258,9 @@ const ScrollResponderMixin = {
/**
* Invoke this from an `onTouchEnd` event.
*
* @param {SyntheticEvent} e Event.
* @param {PressEvent} e Event.
*/
scrollResponderHandleTouchEnd: function(e: Event) {
scrollResponderHandleTouchEnd: function(e: PressEvent) {
const nativeEvent = e.nativeEvent;
this.state.isTouching = nativeEvent.touches.length !== 0;
this.props.onTouchEnd && this.props.onTouchEnd(e);
@ -265,9 +269,9 @@ const ScrollResponderMixin = {
/**
* Invoke this from an `onTouchCancel` event.
*
* @param {SyntheticEvent} e Event.
* @param {PressEvent} e Event.
*/
scrollResponderHandleTouchCancel: function(e: Event) {
scrollResponderHandleTouchCancel: function(e: PressEvent) {
this.state.isTouching = false;
this.props.onTouchCancel && this.props.onTouchCancel(e);
},
@ -275,7 +279,7 @@ const ScrollResponderMixin = {
/**
* Invoke this from an `onResponderRelease` event.
*/
scrollResponderHandleResponderRelease: function(e: Event) {
scrollResponderHandleResponderRelease: function(e: PressEvent) {
this.props.onResponderRelease && this.props.onResponderRelease(e);
// By default scroll views will unfocus a textField
@ -295,7 +299,7 @@ const ScrollResponderMixin = {
}
},
scrollResponderHandleScroll: function(e: Event) {
scrollResponderHandleScroll: function(e: ScrollEvent) {
this.state.observedScrollSinceBecomingResponder = true;
this.props.onScroll && this.props.onScroll(e);
},
@ -303,7 +307,7 @@ const ScrollResponderMixin = {
/**
* Invoke this from an `onResponderGrant` event.
*/
scrollResponderHandleResponderGrant: function(e: Event) {
scrollResponderHandleResponderGrant: function(e: ScrollEvent) {
this.state.observedScrollSinceBecomingResponder = false;
this.props.onResponderGrant && this.props.onResponderGrant(e);
this.state.becameResponderWhileAnimating = this.scrollResponderIsAnimating();
@ -316,7 +320,7 @@ const ScrollResponderMixin = {
*
* Invoke this from an `onScrollBeginDrag` event.
*/
scrollResponderHandleScrollBeginDrag: function(e: Event) {
scrollResponderHandleScrollBeginDrag: function(e: ScrollEvent) {
FrameRateLogger.beginScroll(); // TODO: track all scrolls after implementing onScrollEndAnimation
this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e);
},
@ -324,7 +328,7 @@ const ScrollResponderMixin = {
/**
* Invoke this from an `onScrollEndDrag` event.
*/
scrollResponderHandleScrollEndDrag: function(e: Event) {
scrollResponderHandleScrollEndDrag: function(e: ScrollEvent) {
const {velocity} = e.nativeEvent;
// - If we are animating, then this is a "drag" that is stopping the scrollview and momentum end
// will fire.
@ -343,7 +347,7 @@ const ScrollResponderMixin = {
/**
* Invoke this from an `onMomentumScrollBegin` event.
*/
scrollResponderHandleMomentumScrollBegin: function(e: Event) {
scrollResponderHandleMomentumScrollBegin: function(e: ScrollEvent) {
this.state.lastMomentumScrollBeginTime = performanceNow();
this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e);
},
@ -351,7 +355,7 @@ const ScrollResponderMixin = {
/**
* Invoke this from an `onMomentumScrollEnd` event.
*/
scrollResponderHandleMomentumScrollEnd: function(e: Event) {
scrollResponderHandleMomentumScrollEnd: function(e: ScrollEvent) {
FrameRateLogger.endScroll();
this.state.lastMomentumScrollEndTime = performanceNow();
this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd(e);
@ -366,9 +370,9 @@ const ScrollResponderMixin = {
* responder). The `onResponderReject` won't fire in that case - it only
* fires when a *current* responder rejects our request.
*
* @param {SyntheticEvent} e Touch Start event.
* @param {PressEvent} e Touch Start event.
*/
scrollResponderHandleTouchStart: function(e: Event) {
scrollResponderHandleTouchStart: function(e: PressEvent) {
this.state.isTouching = true;
this.props.onTouchStart && this.props.onTouchStart(e);
},
@ -382,9 +386,9 @@ const ScrollResponderMixin = {
* responder). The `onResponderReject` won't fire in that case - it only
* fires when a *current* responder rejects our request.
*
* @param {SyntheticEvent} e Touch Start event.
* @param {PressEvent} e Touch Start event.
*/
scrollResponderHandleTouchMove: function(e: Event) {
scrollResponderHandleTouchMove: function(e: PressEvent) {
this.props.onTouchMove && this.props.onTouchMove(e);
},
@ -409,7 +413,7 @@ const ScrollResponderMixin = {
* Components can pass what node to use by defining a `getScrollableNode`
* function otherwise `this` is used.
*/
scrollResponderGetScrollableNode: function(): any {
scrollResponderGetScrollableNode: function(): ?number {
return this.getScrollableNode
? this.getScrollableNode()
: ReactNative.findNodeHandle(this);
@ -527,14 +531,14 @@ const ScrollResponderMixin = {
* This method should be used as the callback to onFocus in a TextInputs'
* parent view. Note that any module using this mixin needs to return
* the parent view's ref in getScrollViewRef() in order to use this method.
* @param {any} nodeHandle The TextInput node handle
* @param {number} nodeHandle The TextInput node handle
* @param {number} additionalOffset The scroll view's bottom "contentInset".
* Default is 0.
* @param {bool} preventNegativeScrolling Whether to allow pulling the content
* down to make it meet the keyboard's top. Default is false.
*/
scrollResponderScrollNativeHandleToKeyboard: function(
nodeHandle: any,
nodeHandle: number,
additionalOffset?: number,
preventNegativeScrollOffset?: boolean,
) {
@ -584,8 +588,8 @@ const ScrollResponderMixin = {
this.preventNegativeScrollOffset = false;
},
scrollResponderTextInputFocusError: function(e: Event) {
console.error('Error measuring text field: ', e);
scrollResponderTextInputFocusError: function(msg: string) {
console.error('Error measuring text field: ', msg);
},
/**
@ -667,17 +671,17 @@ const ScrollResponderMixin = {
* relevant to you. (For example, only if you receive these callbacks after
* you had explicitly focused a node etc).
*/
scrollResponderKeyboardWillShow: function(e: Event) {
scrollResponderKeyboardWillShow: function(e: KeyboardEvent) {
this.keyboardWillOpenTo = e;
this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e);
},
scrollResponderKeyboardWillHide: function(e: Event) {
scrollResponderKeyboardWillHide: function(e: KeyboardEvent) {
this.keyboardWillOpenTo = null;
this.props.onKeyboardWillHide && this.props.onKeyboardWillHide(e);
},
scrollResponderKeyboardDidShow: function(e: Event) {
scrollResponderKeyboardDidShow: function(e: KeyboardEvent) {
// TODO(7693961): The event for DidShow is not available on iOS yet.
// Use the one from WillShow and do not assign.
if (e) {
@ -686,7 +690,7 @@ const ScrollResponderMixin = {
this.props.onKeyboardDidShow && this.props.onKeyboardDidShow(e);
},
scrollResponderKeyboardDidHide: function(e: Event) {
scrollResponderKeyboardDidHide: function(e: KeyboardEvent) {
this.keyboardWillOpenTo = null;
this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e);
},

Просмотреть файл

@ -396,8 +396,8 @@ export type Props = $ReadOnly<{|
* - `false`, deprecated, use 'never' instead
* - `true`, deprecated, use 'always' instead
*/
/* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error
* found when Flow v0.85 was deployed. To see the error, delete this comment
/* $FlowFixMe(>=0.86.0 site=react_native_fb) This comment suppresses an error
* found when Flow v0.86 was deployed. To see the error, delete this comment
* and run Flow. */
keyboardShouldPersistTaps?: ?('always' | 'never' | 'handled' | false | true),
/**

Просмотреть файл

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
* @flow strict-local
*/
'use strict';
@ -103,13 +103,56 @@ type Props = $ReadOnly<{|
barStyle?: ?('default' | 'light-content' | 'dark-content'),
|}>;
type StackEntryProps = {|
/**
* The background color of the status bar.
*
* @platform android
*/
backgroundColor: {|
value: ?string,
animated: ?boolean,
|},
/**
* Sets the color of the status bar text.
*/
barStyle: {|
value: ?string,
animated: ?boolean,
|},
/**
* If the status bar is translucent.
* When translucent is set to true, the app will draw under the status bar.
* This is useful when using a semi transparent status bar color.
*/
translucent: ?boolean,
/**
*
*/
hidden: {|
value: ?boolean,
animated: boolean,
transition: ?('slide' | 'fade'),
|},
/**
* If the network activity indicator should be visible.
*
* @platform ios
*/
networkActivityIndicatorVisible: ?boolean,
|};
/**
* Merges the prop stack with the default values.
*/
function mergePropsStack(
propsStack: Array<Object>,
defaultValues: Object,
): Object {
propsStack: $ReadOnlyArray<StackEntryProps>,
defaultValues: StackEntryProps,
): StackEntryProps {
const init: StackEntryProps = {
...defaultValues,
};
return propsStack.reduce((prev, cur) => {
for (const prop in cur) {
if (cur[prop] != null) {
@ -117,39 +160,31 @@ function mergePropsStack(
}
}
return prev;
}, Object.assign({}, defaultValues));
}, init);
}
/**
* Returns an object to insert in the props stack from the props
* and the transition/animation info.
*/
function createStackEntry(props: any): any {
function createStackEntry(props: Props): StackEntryProps {
return {
backgroundColor:
props.backgroundColor != null
? {
value: props.backgroundColor,
animated: props.animated,
}
: null,
barStyle:
props.barStyle != null
? {
value: props.barStyle,
animated: props.animated,
}
: null,
translucent: props.translucent,
hidden:
props.hidden != null
? {
value: props.hidden,
animated: props.animated,
transition: props.showHideTransition,
}
: null,
networkActivityIndicatorVisible: props.networkActivityIndicatorVisible,
backgroundColor: {
value: props.backgroundColor,
animated: props.animated,
},
barStyle: {
value: props.barStyle,
animated: props.animated,
},
translucent: props.translucent || false,
hidden: {
value: props.hidden,
animated: props.animated || false,
transition: props.showHideTransition,
},
networkActivityIndicatorVisible:
props.networkActivityIndicatorVisible || false,
};
}
@ -193,9 +228,9 @@ function createStackEntry(props: any): any {
* `currentHeight` (Android only) The height of the status bar.
*/
class StatusBar extends React.Component<Props> {
static _propsStack = [];
static _propsStack: Array<StackEntryProps> = [];
static _defaultProps = createStackEntry({
static _defaultProps: StackEntryProps = createStackEntry({
animated: false,
showHideTransition: 'fade',
backgroundColor: 'black',
@ -230,10 +265,9 @@ class StatusBar extends React.Component<Props> {
* changing the status bar hidden property.
*/
static setHidden(hidden: boolean, animation?: StatusBarAnimation) {
animation = animation || 'none';
StatusBar._defaultProps.hidden.value = hidden;
if (Platform.OS === 'ios') {
StatusBarManager.setHidden(hidden, animation);
StatusBarManager.setHidden(hidden, animation || 'none');
} else if (Platform.OS === 'android') {
StatusBarManager.setHidden(hidden);
}
@ -245,10 +279,9 @@ class StatusBar extends React.Component<Props> {
* @param animated Animate the style change.
*/
static setBarStyle(style: StatusBarStyle, animated?: boolean) {
animated = animated || false;
StatusBar._defaultProps.barStyle.value = style;
if (Platform.OS === 'ios') {
StatusBarManager.setStyle(style, animated);
StatusBarManager.setStyle(style, animated || false);
} else if (Platform.OS === 'android') {
StatusBarManager.setStyle(style);
}
@ -279,9 +312,8 @@ class StatusBar extends React.Component<Props> {
console.warn('`setBackgroundColor` is only available on Android');
return;
}
animated = animated || false;
StatusBar._defaultProps.backgroundColor.value = color;
StatusBarManager.setColor(processColor(color), animated);
StatusBarManager.setColor(processColor(color), animated || false);
}
/**

Просмотреть файл

@ -34,6 +34,8 @@ const warning = require('fbjs/lib/warning');
import type {TextStyleProp, ViewStyleProp} from 'StyleSheet';
import type {ColorValue} from 'StyleSheetTypes';
import type {ViewProps} from 'ViewPropTypes';
import type {SyntheticEvent, ScrollEvent} from 'CoreEventTypes';
import type {PressEvent} from 'CoreEventTypes';
let AndroidTextInput;
let RCTMultilineTextInputView;
@ -55,11 +57,73 @@ const onlyMultiline = {
children: true,
};
type Event = Object;
type Selection = {
export type ChangeEvent = SyntheticEvent<
$ReadOnly<{|
eventCount: number,
target: number,
text: string,
|}>,
>;
export type TextInputEvent = SyntheticEvent<
$ReadOnly<{|
eventCount: number,
previousText: string,
range: $ReadOnly<{|
start: number,
end: number,
|}>,
target: number,
text: string,
|}>,
>;
export type ContentSizeChangeEvent = SyntheticEvent<
$ReadOnly<{|
target: number,
contentSize: $ReadOnly<{|
width: number,
height: number,
|}>,
|}>,
>;
type TargetEvent = SyntheticEvent<
$ReadOnly<{|
target: number,
|}>,
>;
export type BlurEvent = TargetEvent;
export type FocusEvent = TargetEvent;
type Selection = $ReadOnly<{|
start: number,
end?: number,
};
end: number,
|}>;
export type SelectionChangeEvent = SyntheticEvent<
$ReadOnly<{|
selection: Selection,
target: number,
|}>,
>;
export type KeyPressEvent = SyntheticEvent<
$ReadOnly<{|
key: string,
target?: ?number,
eventCount?: ?number,
|}>,
>;
export type EditingEvent = SyntheticEvent<
$ReadOnly<{|
eventCount: number,
text: string,
target: number,
|}>,
>;
const DataDetectorTypes = [
'phoneNumber',
@ -184,17 +248,17 @@ type Props = $ReadOnly<{|
returnKeyType?: ?ReturnKeyType,
maxLength?: ?number,
multiline?: ?boolean,
onBlur?: ?Function,
onFocus?: ?Function,
onChange?: ?Function,
onChangeText?: ?Function,
onContentSizeChange?: ?Function,
onTextInput?: ?Function,
onEndEditing?: ?Function,
onSelectionChange?: ?Function,
onSubmitEditing?: ?Function,
onKeyPress?: ?Function,
onScroll?: ?Function,
onBlur?: ?(e: BlurEvent) => void,
onFocus?: ?(e: FocusEvent) => void,
onChange?: ?(e: ChangeEvent) => void,
onChangeText?: ?(text: string) => void,
onContentSizeChange?: ?(e: ContentSizeChangeEvent) => void,
onTextInput?: ?(e: TextInputEvent) => void,
onEndEditing?: ?(e: EditingEvent) => void,
onSelectionChange?: ?(e: SelectionChangeEvent) => void,
onSubmitEditing?: ?(e: EditingEvent) => void,
onKeyPress?: ?(e: KeyPressEvent) => void,
onScroll?: ?(e: ScrollEvent) => void,
placeholder?: ?Stringish,
placeholderTextColor?: ?ColorValue,
secureTextEntry?: ?boolean,
@ -792,7 +856,7 @@ const TextInput = createReactClass({
'oneTimeCode',
]),
},
getDefaultProps(): Object {
getDefaultProps() {
return {
allowFontScaling: true,
underlineColorAndroid: 'transparent',
@ -1108,7 +1172,7 @@ const TextInput = createReactClass({
);
},
_onFocus: function(event: Event) {
_onFocus: function(event: FocusEvent) {
if (this.props.onFocus) {
this.props.onFocus(event);
}
@ -1118,16 +1182,16 @@ const TextInput = createReactClass({
}
},
_onPress: function(event: Event) {
_onPress: function(event: PressEvent) {
if (this.props.editable || this.props.editable === undefined) {
this.focus();
}
},
_onChange: function(event: Event) {
_onChange: function(event: ChangeEvent) {
// Make sure to fire the mostRecentEventCount first so it is already set on
// native when the text value is set.
if (this._inputRef) {
if (this._inputRef && this._inputRef.setNativeProps) {
this._inputRef.setNativeProps({
mostRecentEventCount: event.nativeEvent.eventCount,
});
@ -1147,7 +1211,7 @@ const TextInput = createReactClass({
this.forceUpdate();
},
_onSelectionChange: function(event: Event) {
_onSelectionChange: function(event: SelectionChangeEvent) {
this.props.onSelectionChange && this.props.onSelectionChange(event);
if (!this._inputRef) {
@ -1188,7 +1252,11 @@ const TextInput = createReactClass({
nativeProps.selection = this.props.selection;
}
if (Object.keys(nativeProps).length > 0 && this._inputRef) {
if (
Object.keys(nativeProps).length > 0 &&
this._inputRef &&
this._inputRef.setNativeProps
) {
this._inputRef.setNativeProps(nativeProps);
}
@ -1197,8 +1265,7 @@ const TextInput = createReactClass({
}
},
_onBlur: function(event: Event) {
this.blur();
_onBlur: function(event: BlurEvent) {
if (this.props.onBlur) {
this.props.onBlur(event);
}
@ -1208,11 +1275,11 @@ const TextInput = createReactClass({
}
},
_onTextInput: function(event: Event) {
_onTextInput: function(event: TextInputEvent) {
this.props.onTextInput && this.props.onTextInput(event);
},
_onScroll: function(event: Event) {
_onScroll: function(event: ScrollEvent) {
this.props.onScroll && this.props.onScroll(event);
},
});

Просмотреть файл

@ -0,0 +1,70 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+react_native
* @format
* @flow-strict
*/
'use strict';
const React = require('React');
const ReactTestRenderer = require('react-test-renderer');
const TextInput = require('TextInput');
import Component from '@reactions/component';
const {enter} = require('ReactNativeTestTools');
jest.unmock('TextInput');
describe('TextInput tests', () => {
let input;
let onChangeListener;
let onChangeTextListener;
const initialValue = 'initialValue';
beforeEach(() => {
onChangeListener = jest.fn();
onChangeTextListener = jest.fn();
const renderTree = ReactTestRenderer.create(
<Component initialState={{text: initialValue}}>
{({setState, state}) => (
<TextInput
value={state.text}
onChangeText={text => {
onChangeTextListener(text);
setState({text});
}}
onChange={event => {
onChangeListener(event);
}}
/>
)}
</Component>,
);
input = renderTree.root.findByType(TextInput);
});
it('has expected instance functions', () => {
expect(input.instance.isFocused).toBeInstanceOf(Function); // Would have prevented S168585
expect(input.instance.clear).toBeInstanceOf(Function);
expect(input.instance.focus).toBeInstanceOf(Function);
expect(input.instance.blur).toBeInstanceOf(Function);
expect(input.instance.setNativeProps).toBeInstanceOf(Function);
expect(input.instance.measure).toBeInstanceOf(Function);
expect(input.instance.measureInWindow).toBeInstanceOf(Function);
expect(input.instance.measureLayout).toBeInstanceOf(Function);
});
it('calls onChange callbacks', () => {
expect(input.props.value).toBe(initialValue);
const message = 'This is a test message';
enter(input, message);
expect(input.props.value).toBe(message);
expect(onChangeTextListener).toHaveBeenCalledWith(message);
expect(onChangeListener).toHaveBeenCalledWith({
nativeEvent: {text: message},
});
});
});

Просмотреть файл

@ -5,13 +5,18 @@
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
* @flow strict-local
*/
'use strict';
const TimePickerModule = require('NativeModules').TimePickerAndroid;
import type {
TimePickerOptions,
TimePickerResult,
} from './TimePickerAndroidTypes';
/**
* Opens the standard Android time picker dialog.
*
@ -52,22 +57,18 @@ class TimePickerAndroid {
* still be resolved with action being `TimePickerAndroid.dismissedAction` and all the other keys
* being undefined. **Always** check whether the `action` before reading the values.
*/
static async open(options: Object): Promise<Object> {
static async open(options: TimePickerOptions): Promise<TimePickerResult> {
return TimePickerModule.open(options);
}
/**
* A time has been selected.
*/
static get timeSetAction() {
return 'timeSetAction';
}
static +timeSetAction: 'timeSetAction' = 'timeSetAction';
/**
* The dialog has been dismissed.
*/
static get dismissedAction() {
return 'dismissedAction';
}
static +dismissedAction: 'dismissedAction' = 'dismissedAction';
}
module.exports = TimePickerAndroid;

Просмотреть файл

@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its 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';
export type TimePickerOptions = {|
hour?: number,
minute?: number,
is24Hour?: boolean,
mode?: 'clock' | 'spinner' | 'default',
|};
export type TimePickerResult = $ReadOnly<{|
action: string,
hour: number,
minute: number,
|}>;

Просмотреть файл

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
@ -23,6 +24,9 @@ const View = require('View');
const keyMirror = require('fbjs/lib/keyMirror');
const normalizeColor = require('normalizeColor');
import type {PressEvent} from 'CoreEventTypes';
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
/**
* `Touchable`: Taps done right.
*
@ -111,6 +115,7 @@ const normalizeColor = require('normalizeColor');
/**
* Touchable states.
*/
const States = keyMirror({
NOT_RESPONDER: null, // Not the responder
RESPONDER_INACTIVE_PRESS_IN: null, // Responder, inactive, in the `PressRect`
@ -122,10 +127,33 @@ const States = keyMirror({
ERROR: null,
});
/**
type State =
| typeof States.NOT_RESPONDER
| typeof States.RESPONDER_INACTIVE_PRESS_IN
| typeof States.RESPONDER_INACTIVE_PRESS_OUT
| typeof States.RESPONDER_ACTIVE_PRESS_IN
| typeof States.RESPONDER_ACTIVE_PRESS_OUT
| typeof States.RESPONDER_ACTIVE_LONG_PRESS_IN
| typeof States.RESPONDER_ACTIVE_LONG_PRESS_OUT
| typeof States.ERROR;
/*
* Quick lookup map for states that are considered to be "active"
*/
const baseStatesConditions = {
NOT_RESPONDER: false,
RESPONDER_INACTIVE_PRESS_IN: false,
RESPONDER_INACTIVE_PRESS_OUT: false,
RESPONDER_ACTIVE_PRESS_IN: false,
RESPONDER_ACTIVE_PRESS_OUT: false,
RESPONDER_ACTIVE_LONG_PRESS_IN: false,
RESPONDER_ACTIVE_LONG_PRESS_OUT: false,
ERROR: false,
};
const IsActive = {
...baseStatesConditions,
RESPONDER_ACTIVE_PRESS_OUT: true,
RESPONDER_ACTIVE_PRESS_IN: true,
};
@ -135,12 +163,14 @@ const IsActive = {
* therefore eligible to result in a "selection" if the press stops.
*/
const IsPressingIn = {
...baseStatesConditions,
RESPONDER_INACTIVE_PRESS_IN: true,
RESPONDER_ACTIVE_PRESS_IN: true,
RESPONDER_ACTIVE_LONG_PRESS_IN: true,
};
const IsLongPressingIn = {
...baseStatesConditions,
RESPONDER_ACTIVE_LONG_PRESS_IN: true,
};
@ -157,6 +187,15 @@ const Signals = keyMirror({
LONG_PRESS_DETECTED: null,
});
type Signal =
| typeof Signals.DELAY
| typeof Signals.RESPONDER_GRANT
| typeof Signals.RESPONDER_RELEASE
| typeof Signals.RESPONDER_TERMINATED
| typeof Signals.ENTER_PRESS_RECT
| typeof Signals.LEAVE_PRESS_RECT
| typeof Signals.LONG_PRESS_DETECTED;
/**
* Mapping from States x Signals => States
*/
@ -391,7 +430,7 @@ const TouchableMixin = {
* @param {SyntheticEvent} e Synthetic event from event system.
*
*/
touchableHandleResponderGrant: function(e) {
touchableHandleResponderGrant: function(e: PressEvent) {
const dispatchID = e.currentTarget;
// Since e is used in a callback invoked on another event loop
// (as in setTimeout etc), we need to call e.persist() on the
@ -432,21 +471,21 @@ const TouchableMixin = {
/**
* Place as callback for a DOM element's `onResponderRelease` event.
*/
touchableHandleResponderRelease: function(e) {
touchableHandleResponderRelease: function(e: PressEvent) {
this._receiveSignal(Signals.RESPONDER_RELEASE, e);
},
/**
* Place as callback for a DOM element's `onResponderTerminate` event.
*/
touchableHandleResponderTerminate: function(e) {
touchableHandleResponderTerminate: function(e: PressEvent) {
this._receiveSignal(Signals.RESPONDER_TERMINATED, e);
},
/**
* Place as callback for a DOM element's `onResponderMove` event.
*/
touchableHandleResponderMove: function(e) {
touchableHandleResponderMove: function(e: PressEvent) {
// Not enough time elapsed yet, wait for highlight -
// this is just a perf optimization.
if (
@ -633,7 +672,14 @@ const TouchableMixin = {
UIManager.measure(tag, this._handleQueryLayout);
},
_handleQueryLayout: function(l, t, w, h, globalX, globalY) {
_handleQueryLayout: function(
l: number,
t: number,
w: number,
h: number,
globalX: number,
globalY: number,
) {
//don't do anything UIManager failed to measure node
if (!l && !t && !w && !h && !globalX && !globalY) {
return;
@ -652,12 +698,12 @@ const TouchableMixin = {
);
},
_handleDelay: function(e) {
_handleDelay: function(e: PressEvent) {
this.touchableDelayTimeout = null;
this._receiveSignal(Signals.DELAY, e);
},
_handleLongDelay: function(e) {
_handleLongDelay: function(e: PressEvent) {
this.longPressDelayTimeout = null;
const curState = this.state.touchable.touchState;
if (
@ -685,7 +731,7 @@ const TouchableMixin = {
* @throws Error if invalid state transition or unrecognized signal.
* @sideeffects
*/
_receiveSignal: function(signal, e) {
_receiveSignal: function(signal: Signal, e: PressEvent) {
const responderID = this.state.touchable.responderID;
const curState = this.state.touchable.touchState;
const nextState = Transitions[curState] && Transitions[curState][signal];
@ -725,14 +771,14 @@ const TouchableMixin = {
this.longPressDelayTimeout = null;
},
_isHighlight: function(state) {
_isHighlight: function(state: State) {
return (
state === States.RESPONDER_ACTIVE_PRESS_IN ||
state === States.RESPONDER_ACTIVE_LONG_PRESS_IN
);
},
_savePressInLocation: function(e) {
_savePressInLocation: function(e: PressEvent) {
const touch = TouchEventUtils.extractSingleTouch(e.nativeEvent);
const pageX = touch && touch.pageX;
const pageY = touch && touch.pageY;
@ -741,7 +787,12 @@ const TouchableMixin = {
this.pressInLocation = {pageX, pageY, locationX, locationY};
},
_getDistanceBetweenPoints: function(aX, aY, bX, bY) {
_getDistanceBetweenPoints: function(
aX: number,
aY: number,
bX: number,
bY: number,
) {
const deltaX = aX - bX;
const deltaY = aY - bY;
return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
@ -758,7 +809,12 @@ const TouchableMixin = {
* @param {Event} e Native event.
* @sideeffects
*/
_performSideEffectsForTransition: function(curState, nextState, signal, e) {
_performSideEffectsForTransition: function(
curState: State,
nextState: State,
signal: Signal,
e: PressEvent,
) {
const curIsHighlight = this._isHighlight(curState);
const newIsHighlight = this._isHighlight(nextState);
@ -813,12 +869,12 @@ const TouchableMixin = {
UIManager.playTouchSound();
},
_startHighlight: function(e) {
_startHighlight: function(e: PressEvent) {
this._savePressInLocation(e);
this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e);
},
_endHighlight: function(e) {
_endHighlight: function(e: PressEvent) {
if (this.touchableHandleActivePressOut) {
if (
this.touchableGetPressOutDelayMS &&
@ -840,7 +896,13 @@ const Touchable = {
/**
* Renders a debugging overlay to visualize touch target with hitSlop (might not work on Android).
*/
renderDebugView: ({color, hitSlop}) => {
renderDebugView: ({
color,
hitSlop,
}: {
color: string | number,
hitSlop: EdgeInsetsProp,
}) => {
if (!Touchable.TOUCH_TARGET_DEBUG) {
return null;
}
@ -854,8 +916,12 @@ const Touchable = {
for (const key in hitSlop) {
debugHitSlopStyle[key] = -hitSlop[key];
}
const normalizedColor = normalizeColor(color);
if (typeof normalizedColor !== 'number') {
return null;
}
const hexColor =
'#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8);
'#' + ('00000000' + normalizedColor.toString(16)).substr(-8);
return (
<View
pointerEvents="none"

Просмотреть файл

@ -23,8 +23,7 @@ const createReactClass = require('create-react-class');
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
import type {ViewStyleProp} from 'StyleSheet';
import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback';
type Event = Object;
import type {PressEvent} from 'CoreEventTypes';
type State = {
animationID: ?number,
@ -36,8 +35,8 @@ const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
type Props = $ReadOnly<{|
...TouchableWithoutFeedbackProps,
onPressWithCompletion?: ?Function,
onPressAnimationComplete?: ?Function,
onPressWithCompletion?: ?(fn: () => void) => void,
onPressAnimationComplete?: ?() => void,
pressRetentionOffset?: ?EdgeInsetsProp,
releaseVelocity?: ?number,
releaseBounciness?: ?number,
@ -95,7 +94,7 @@ const TouchableBounce = ((createReactClass({
value: number,
velocity: number,
bounciness: number,
callback?: ?Function,
callback?: ?() => void,
) {
Animated.spring(this.state.scale, {
toValue: value,
@ -105,21 +104,28 @@ const TouchableBounce = ((createReactClass({
}).start(callback);
},
/**
* Triggers a bounce animation without invoking any callbacks.
*/
bounce: function() {
this.bounceTo(0.93, 0.1, 0, () => this.bounceTo(1, 0.4, 0));
},
/**
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
* defined on your component.
*/
touchableHandleActivePressIn: function(e: Event) {
touchableHandleActivePressIn: function(e: PressEvent) {
this.bounceTo(0.93, 0.1, 0);
this.props.onPressIn && this.props.onPressIn(e);
},
touchableHandleActivePressOut: function(e: Event) {
touchableHandleActivePressOut: function(e: PressEvent) {
this.bounceTo(1, 0.4, 0);
this.props.onPressOut && this.props.onPressOut(e);
},
touchableHandlePress: function(e: Event) {
touchableHandlePress: function(e: PressEvent) {
const onPressWithCompletion = this.props.onPressWithCompletion;
if (onPressWithCompletion) {
onPressWithCompletion(() => {
@ -147,7 +153,7 @@ const TouchableBounce = ((createReactClass({
return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET;
},
touchableGetHitSlop: function(): ?Object {
touchableGetHitSlop: function(): ?EdgeInsetsProp {
return this.props.hitSlop;
},

Просмотреть файл

@ -28,6 +28,7 @@ import type {PressEvent} from 'CoreEventTypes';
import type {ViewStyleProp} from 'StyleSheet';
import type {ColorValue} from 'StyleSheetTypes';
import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback';
import type {TVParallaxPropertiesType} from 'TVViewPropTypes';
const DEFAULT_PROPS = {
activeOpacity: 0.85,
@ -39,7 +40,7 @@ const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
type IOSProps = $ReadOnly<{|
hasTVPreferredFocus?: ?boolean,
tvParallaxProperties?: ?Object,
tvParallaxProperties?: ?TVParallaxPropertiesType,
|}>;
type Props = $ReadOnly<{|
@ -49,8 +50,8 @@ type Props = $ReadOnly<{|
activeOpacity?: ?number,
underlayColor?: ?ColorValue,
style?: ?ViewStyleProp,
onShowUnderlay?: ?Function,
onHideUnderlay?: ?Function,
onShowUnderlay?: ?() => void,
onHideUnderlay?: ?() => void,
testOnly_pressed?: ?boolean,
|}>;
@ -185,18 +186,7 @@ const TouchableHighlight = ((createReactClass({
*/
hasTVPreferredFocus: PropTypes.bool,
/**
* *(Apple TV only)* Object with properties to control Apple TV parallax effects.
*
* enabled: If true, parallax effects are enabled. Defaults to true.
* shiftDistanceX: Defaults to 2.0.
* shiftDistanceY: Defaults to 2.0.
* tiltAngle: Defaults to 0.05.
* magnification: Defaults to 1.0.
* pressMagnification: Defaults to 1.0.
* pressDuration: Defaults to 0.3.
* pressDelay: Defaults to 0.0.
*
* @platform ios
* Apple TV parallax effects
*/
tvParallaxProperties: PropTypes.object,
/**

Просмотреть файл

@ -4,6 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
@ -22,6 +23,8 @@ const createReactClass = require('create-react-class');
const ensurePositiveDelayProps = require('ensurePositiveDelayProps');
const processColor = require('processColor');
import type {PressEvent} from 'CoreEventTypes';
const rippleBackgroundPropType = PropTypes.shape({
type: PropTypes.oneOf(['RippleAndroid']),
color: PropTypes.number,
@ -38,8 +41,6 @@ const backgroundPropType = PropTypes.oneOfType([
themeAttributeBackgroundPropType,
]);
type Event = Object;
const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30};
/**
@ -167,7 +168,7 @@ const TouchableNativeFeedback = createReactClass({
* `Touchable.Mixin` self callbacks. The mixin will invoke these if they are
* defined on your component.
*/
touchableHandleActivePressIn: function(e: Event) {
touchableHandleActivePressIn: function(e: PressEvent) {
this.props.onPressIn && this.props.onPressIn(e);
this._dispatchPressedStateChange(true);
if (this.pressInLocation) {
@ -178,16 +179,16 @@ const TouchableNativeFeedback = createReactClass({
}
},
touchableHandleActivePressOut: function(e: Event) {
touchableHandleActivePressOut: function(e: PressEvent) {
this.props.onPressOut && this.props.onPressOut(e);
this._dispatchPressedStateChange(false);
},
touchableHandlePress: function(e: Event) {
touchableHandlePress: function(e: PressEvent) {
this.props.onPress && this.props.onPress(e);
},
touchableHandleLongPress: function(e: Event) {
touchableHandleLongPress: function(e: PressEvent) {
this.props.onLongPress && this.props.onLongPress(e);
},

Просмотреть файл

@ -33,12 +33,18 @@ const UIManagerStatTracker = {
const createViewOrig = UIManager.createView;
UIManager.createView = function(tag, className, rootTag, props) {
incStat('createView', 1);
/* $FlowFixMe(>=0.86.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.86 was deployed. To see the error, delete
* this comment and run Flow. */
incStat('setProp', Object.keys(props || []).length);
createViewOrig(tag, className, rootTag, props);
};
const updateViewOrig = UIManager.updateView;
UIManager.updateView = function(tag, className, props) {
incStat('updateView', 1);
/* $FlowFixMe(>=0.86.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.86 was deployed. To see the error, delete
* this comment and run Flow. */
incStat('setProp', Object.keys(props || []).length);
updateViewOrig(tag, className, props);
};
@ -52,7 +58,13 @@ const UIManagerStatTracker = {
remove,
) {
incStat('manageChildren', 1);
/* $FlowFixMe(>=0.86.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.86 was deployed. To see the error, delete
* this comment and run Flow. */
incStat('move', Object.keys(moveFrom || []).length);
/* $FlowFixMe(>=0.86.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.86 was deployed. To see the error, delete
* this comment and run Flow. */
incStat('remove', Object.keys(remove || []).length);
manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove);
};

Просмотреть файл

@ -49,8 +49,8 @@ function renderApplication<Props: Object>(
RootComponent.prototype.unstable_isAsyncReactComponent === true
) {
// $FlowFixMe This is not yet part of the official public API
const AsyncMode = React.unstable_AsyncMode;
renderable = <AsyncMode>{renderable}</AsyncMode>;
const ConcurrentMode = React.unstable_ConcurrentMode;
renderable = <ConcurrentMode>{renderable}</ConcurrentMode>;
}
if (fabric) {

Просмотреть файл

@ -339,7 +339,7 @@ module.exports = {
) {
let value;
if (typeof ReactNativeStyleAttributes[property] === 'string') {
if (ReactNativeStyleAttributes[property] === true) {
value = {};
} else if (typeof ReactNativeStyleAttributes[property] === 'object') {
value = ReactNativeStyleAttributes[property];

Просмотреть файл

@ -27,10 +27,10 @@ import type {PressRetentionOffset, TextProps} from 'TextProps';
type ResponseHandlers = $ReadOnly<{|
onStartShouldSetResponder: () => boolean,
onResponderGrant: (event: SyntheticEvent<>, dispatchID: string) => void,
onResponderMove: (event: SyntheticEvent<>) => void,
onResponderRelease: (event: SyntheticEvent<>) => void,
onResponderTerminate: (event: SyntheticEvent<>) => void,
onResponderGrant: (event: PressEvent, dispatchID: string) => void,
onResponderMove: (event: PressEvent) => void,
onResponderRelease: (event: PressEvent) => void,
onResponderTerminate: (event: PressEvent) => void,
onResponderTerminationRequest: () => boolean,
|}>;
@ -93,12 +93,12 @@ class TouchableText extends React.Component<Props, State> {
touchableHandleLongPress: ?(event: PressEvent) => void;
touchableHandlePress: ?(event: PressEvent) => void;
touchableHandleResponderGrant: ?(
event: SyntheticEvent<>,
event: PressEvent,
dispatchID: string,
) => void;
touchableHandleResponderMove: ?(event: SyntheticEvent<>) => void;
touchableHandleResponderRelease: ?(event: SyntheticEvent<>) => void;
touchableHandleResponderTerminate: ?(event: SyntheticEvent<>) => void;
touchableHandleResponderMove: ?(event: PressEvent) => void;
touchableHandleResponderRelease: ?(event: PressEvent) => void;
touchableHandleResponderTerminate: ?(event: PressEvent) => void;
touchableHandleResponderTerminationRequest: ?() => boolean;
state = {
@ -173,25 +173,25 @@ class TouchableText extends React.Component<Props, State> {
}
return shouldSetResponder;
},
onResponderGrant: (event: SyntheticEvent<>, dispatchID: string): void => {
onResponderGrant: (event: PressEvent, dispatchID: string): void => {
nullthrows(this.touchableHandleResponderGrant)(event, dispatchID);
if (this.props.onResponderGrant != null) {
this.props.onResponderGrant.call(this, event, dispatchID);
}
},
onResponderMove: (event: SyntheticEvent<>): void => {
onResponderMove: (event: PressEvent): void => {
nullthrows(this.touchableHandleResponderMove)(event);
if (this.props.onResponderMove != null) {
this.props.onResponderMove.call(this, event);
}
},
onResponderRelease: (event: SyntheticEvent<>): void => {
onResponderRelease: (event: PressEvent): void => {
nullthrows(this.touchableHandleResponderRelease)(event);
if (this.props.onResponderRelease != null) {
this.props.onResponderRelease.call(this, event);
}
},
onResponderTerminate: (event: SyntheticEvent<>): void => {
onResponderTerminate: (event: PressEvent): void => {
nullthrows(this.touchableHandleResponderTerminate)(event);
if (this.props.onResponderTerminate != null) {
this.props.onResponderTerminate.call(this, event);

Просмотреть файл

@ -290,6 +290,9 @@
RCTRoundPixelValue(attachmentSize.width),
RCTRoundPixelValue(attachmentSize.height)
}};
NSRange truncatedGlyphRange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:range.location];
BOOL viewIsTruncated = NSIntersectionRange(range, truncatedGlyphRange).length != 0;
RCTLayoutContext localLayoutContext = layoutContext;
localLayoutContext.absolutePosition.x += frame.origin.x;
@ -300,9 +303,11 @@
layoutDirection:self.layoutMetrics.layoutDirection
layoutContext:localLayoutContext];
// Reinforcing a proper frame origin for the Shadow View.
RCTLayoutMetrics localLayoutMetrics = shadowView.layoutMetrics;
localLayoutMetrics.frame.origin = frame.origin;
localLayoutMetrics.frame.origin = frame.origin; // Reinforcing a proper frame origin for the Shadow View.
if (viewIsTruncated) {
localLayoutMetrics.displayType = RCTDisplayTypeNone;
}
[shadowView layoutWithMetrics:localLayoutMetrics layoutContext:localLayoutContext];
}
];

Просмотреть файл

@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @flow strict-local
* @format
*/
@ -106,12 +106,12 @@ export type TextProps = $ReadOnly<{
* See https://facebook.github.io/react-native/docs/text.html#onpress
*/
onPress?: ?(event: PressEvent) => mixed,
onResponderGrant?: ?Function,
onResponderMove?: ?Function,
onResponderRelease?: ?Function,
onResponderTerminate?: ?Function,
onResponderTerminationRequest?: ?Function,
onStartShouldSetResponder?: ?Function,
onResponderGrant?: ?(event: PressEvent, dispatchID: string) => void,
onResponderMove?: ?(event: PressEvent) => void,
onResponderRelease?: ?(event: PressEvent) => void,
onResponderTerminate?: ?(event: PressEvent) => void,
onResponderTerminationRequest?: ?() => boolean,
onStartShouldSetResponder?: ?() => boolean,
onTextLayout?: ?(event: TextLayoutEvent) => mixed,
/**

Просмотреть файл

@ -19,8 +19,11 @@ const Platform = {
return constants && constants.Version;
},
get isTesting(): boolean {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
if (__DEV__) {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
}
return false;
},
get isTV(): boolean {
const constants = NativeModules.PlatformConstants;

Просмотреть файл

@ -33,8 +33,11 @@ const Platform = {
return constants ? constants.interfaceIdiom === 'tv' : false;
},
get isTesting(): boolean {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
if (__DEV__) {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
}
return false;
},
select: (obj: Object) => ('ios' in obj ? obj.ios : obj.default),
};

Просмотреть файл

@ -0,0 +1,165 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const React = require('React');
const ReactTestRenderer = require('react-test-renderer');
const {Switch, Text, TextInput, VirtualizedList} = require('react-native');
import type {
ReactTestInstance,
ReactTestRendererNode,
Predicate,
} from 'react-test-renderer';
function byClickable(): Predicate {
return withMessage(
node =>
// note: <Text /> lazy-mounts press handlers after the first press,
// so this is a workaround for targeting text nodes.
(node.type === Text &&
node.props &&
typeof node.props.onPress === 'function') ||
// note: Special casing <Switch /> since it doesn't use touchable
(node.type === Switch && node.props && node.props.disabled !== true) ||
(node.instance &&
typeof node.instance.touchableHandlePress === 'function'),
'is clickable',
);
}
function byTestID(testID: string): Predicate {
return withMessage(
node => node.props && node.props.testID === testID,
`testID prop equals ${testID}`,
);
}
function byTextMatching(regex: RegExp): Predicate {
return withMessage(
node => node.props && regex.exec(node.props.children),
`text content matches ${regex.toString()}`,
);
}
function enter(instance: ReactTestInstance, text: string) {
const input = instance.findByType(TextInput);
input.instance._onChange({nativeEvent: {text}});
}
// Returns null if there is no error, otherwise returns an error message string.
function maximumDepthError(
tree: {toJSON: () => ReactTestRendererNode},
maxDepthLimit: number,
): ?string {
const maxDepth = maximumDepthOfJSON(tree.toJSON());
if (maxDepth > maxDepthLimit) {
return (
`maximumDepth of ${maxDepth} exceeded limit of ${maxDepthLimit} - this is a proxy ` +
'metric to protect against stack overflow errors:\n\n' +
'https://fburl.com/rn-view-stack-overflow.\n\n' +
'To fix, you need to remove native layers from your hierarchy, such as unnecessary View ' +
'wrappers.'
);
} else {
return null;
}
}
function expectNoConsoleWarn() {
(jest: $FlowFixMe).spyOn(console, 'warn').mockImplementation((...args) => {
expect(args).toBeFalsy();
});
}
function expectNoConsoleError() {
let hasNotFailed = true;
(jest: $FlowFixMe).spyOn(console, 'error').mockImplementation((...args) => {
if (hasNotFailed) {
hasNotFailed = false; // set false to prevent infinite recursion
expect(args).toBeFalsy();
}
});
}
// Takes a node from toJSON()
function maximumDepthOfJSON(node: ReactTestRendererNode): number {
if (node == null) {
return 0;
} else if (typeof node === 'string' || node.children == null) {
return 1;
} else {
let maxDepth = 0;
node.children.forEach(child => {
maxDepth = Math.max(maximumDepthOfJSON(child) + 1, maxDepth);
});
return maxDepth;
}
}
function renderAndEnforceStrictMode(element: React.Node) {
expectNoConsoleError();
return renderWithStrictMode(element);
}
function renderWithStrictMode(element: React.Node) {
const WorkAroundBugWithStrictModeInTestRenderer = prps => prps.children;
const StrictMode = (React: $FlowFixMe).StrictMode;
return ReactTestRenderer.create(
<WorkAroundBugWithStrictModeInTestRenderer>
<StrictMode>{element}</StrictMode>
</WorkAroundBugWithStrictModeInTestRenderer>,
);
}
function tap(instance: ReactTestInstance) {
const touchable = instance.find(byClickable());
if (touchable.type === Text && touchable.props && touchable.props.onPress) {
touchable.props.onPress();
} else if (touchable.type === Switch && touchable.props) {
const value = !touchable.props.value;
const {onChange, onValueChange} = touchable.props;
onChange && onChange({nativeEvent: {value}});
onValueChange && onValueChange(value);
} else {
// Only tap when props.disabled isn't set (or there aren't any props)
if (!touchable.props || !touchable.props.disabled) {
touchable.instance.touchableHandlePress({nativeEvent: {}});
}
}
}
function scrollToBottom(instance: ReactTestInstance) {
const list = instance.findByType(VirtualizedList);
list.props && list.props.onEndReached();
}
// To make error messages a little bit better, we attach a custom toString
// implementation to a predicate
function withMessage(fn: Predicate, message: string): Predicate {
(fn: any).toString = () => message;
return fn;
}
export {byClickable};
export {byTestID};
export {byTextMatching};
export {enter};
export {expectNoConsoleWarn};
export {expectNoConsoleError};
export {maximumDepthError};
export {maximumDepthOfJSON};
export {renderAndEnforceStrictMode};
export {renderWithStrictMode};
export {scrollToBottom};
export {tap};
export {withMessage};

Просмотреть файл

@ -12,18 +12,22 @@
const React = require('react');
const ReactNative = require('react-native');
const {AccessibilityInfo, Text, View, TouchableOpacity} = ReactNative;
const {AccessibilityInfo, Text, View, TouchableOpacity, Alert} = ReactNative;
class AccessibilityIOSExample extends React.Component<{}> {
render() {
return (
<View>
<View
onAccessibilityTap={() => alert('onAccessibilityTap success')}
onAccessibilityTap={() =>
Alert.alert('Alert', 'onAccessibilityTap success')
}
accessible={true}>
<Text>Accessibility normal tap example</Text>
</View>
<View onMagicTap={() => alert('onMagicTap success')} accessible={true}>
<View
onMagicTap={() => Alert.alert('Alert', 'onMagicTap success')}
accessible={true}>
<Text>Accessibility magic tap example</Text>
</View>
<View accessibilityLabel="Some announcement" accessible={true}>

Просмотреть файл

@ -12,7 +12,14 @@
const React = require('react');
const ReactNative = require('react-native');
const {ActionSheetIOS, StyleSheet, takeSnapshot, Text, View} = ReactNative;
const {
ActionSheetIOS,
StyleSheet,
takeSnapshot,
Text,
View,
Alert,
} = ReactNative;
const BUTTONS = ['Option 0', 'Option 1', 'Option 2', 'Delete', 'Cancel'];
const DESTRUCTIVE_INDEX = 3;
@ -106,7 +113,7 @@ class ShareActionSheetExample extends React.Component<
subject: 'a subject to go in the email heading',
excludedActivityTypes: ['com.apple.UIKit.activity.PostToTwitter'],
},
error => alert(error),
error => Alert.alert('Error', error),
(completed, method) => {
let text;
if (completed) {
@ -146,7 +153,7 @@ class ShareScreenshotExample extends React.Component<{}, $FlowFixMeState> {
url: uri,
excludedActivityTypes: ['com.apple.UIKit.activity.PostToTwitter'],
},
error => alert(error),
error => Alert.alert('Error', error),
(completed, method) => {
let text;
if (completed) {
@ -158,7 +165,7 @@ class ShareScreenshotExample extends React.Component<{}, $FlowFixMeState> {
},
);
})
.catch(error => alert(error));
.catch(error => Alert.alert('Error', error));
};
}

Просмотреть файл

@ -12,7 +12,7 @@
const React = require('react');
const ReactNative = require('react-native');
const {StyleSheet, Text, View} = ReactNative;
const {StyleSheet, Text, View, Alert} = ReactNative;
exports.framework = 'React';
exports.title = 'Geolocation';
@ -41,7 +41,7 @@ class GeolocationExample extends React.Component<{}, $FlowFixMeState> {
const initialPosition = JSON.stringify(position);
this.setState({initialPosition});
},
error => alert(JSON.stringify(error)),
error => Alert.alert('Error', JSON.stringify(error)),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000},
);
this.watchID = navigator.geolocation.watchPosition(position => {

Просмотреть файл

@ -12,7 +12,7 @@
const React = require('react');
const ReactNative = require('react-native');
const {FlatList, StyleSheet, Text, View} = ReactNative;
const {FlatList, StyleSheet, Text, View, Alert} = ReactNative;
const RNTesterPage = require('./RNTesterPage');
@ -91,7 +91,9 @@ class MultiColumnExample extends React.PureComponent<
data={filteredData}
key={this.state.numColumns + (this.state.fixedHeight ? 'f' : 'v')}
numColumns={this.state.numColumns || 1}
onRefresh={() => alert('onRefresh: nothing to refresh :P')}
onRefresh={() =>
Alert.alert('Alert', 'onRefresh: nothing to refresh :P')
}
refreshing={false}
renderItem={this._renderItemComponent}
disableVirtualization={!this.state.virtualized}

Просмотреть файл

@ -48,7 +48,8 @@ class TextEventsExample extends React.Component<{}, $FlowFixMeState> {
}
onContentSizeChange={event =>
this.updateText(
'onContentSizeChange size: ' + event.nativeEvent.contentSize,
'onContentSizeChange size: ' +
JSON.stringify(event.nativeEvent.contentSize),
)
}
onEndEditing={event =>
@ -253,10 +254,10 @@ class ToggleDefaultPaddingExample extends React.Component<
}
type SelectionExampleState = {
selection: {
selection: $ReadOnly<{|
start: number,
end: number,
},
end?: number,
|}>,
value: string,
};

Просмотреть файл

@ -14,7 +14,7 @@ const Button = require('Button');
const InputAccessoryView = require('InputAccessoryView');
const React = require('react');
const ReactNative = require('react-native');
const {Text, TextInput, View, StyleSheet, Slider, Switch} = ReactNative;
const {Text, TextInput, View, StyleSheet, Slider, Switch, Alert} = ReactNative;
class WithLabel extends React.Component<$FlowFixMeProps> {
render() {
@ -71,7 +71,7 @@ class TextEventsExample extends React.Component<{}, $FlowFixMeState> {
'onSelectionChange range: ' +
event.nativeEvent.selection.start +
',' +
event.nativeEvent.selection.end,
(event.nativeEvent.selection.end || ''),
)
}
onKeyPress={event => {
@ -348,10 +348,10 @@ class BlurOnSubmitExample extends React.Component<{}> {
}
type SelectionExampleState = {
selection: {|
selection: $ReadOnly<{|
start: number,
end?: number,
|},
|}>,
value: string,
};
@ -862,7 +862,9 @@ exports.examples = [
returnKeyType="next"
blurOnSubmit={true}
multiline={true}
onSubmitEditing={event => alert(event.nativeEvent.text)}
onSubmitEditing={event =>
Alert.alert('Alert', event.nativeEvent.text)
}
/>
</View>
);

Просмотреть файл

@ -12,13 +12,13 @@
const React = require('react');
const ReactNative = require('react-native');
const {Text, View, TouchableOpacity} = ReactNative;
const {Text, View, TouchableOpacity, Alert} = ReactNative;
class TransparentHitTestExample extends React.Component<{}> {
render() {
return (
<View style={{flex: 1}}>
<TouchableOpacity onPress={() => alert('Hi!')}>
<TouchableOpacity onPress={() => Alert.alert('Alert', 'Hi!')}>
<Text>HELLO!</Text>
</TouchableOpacity>

Просмотреть файл

@ -27,7 +27,7 @@ class XHRExampleFetch extends React.Component<any, any> {
this.responseHeaders = null;
}
submit(uri: String) {
submit(uri: string) {
fetch(uri)
.then(response => {
this.responseURL = response.url;

Просмотреть файл

@ -35,7 +35,7 @@ server.on('connection', ws => {
console.log('Received message:', message);
console.log('Cookie:', ws.upgradeReq.headers.cookie);
if (respondWithBinary) {
message = new Buffer(message);
message = Buffer.from(message);
}
if (message === 'getImage') {
message = fs.readFileSync(path.resolve(__dirname, 'flux@3x.png'));

87
React/.clang-format Normal file
Просмотреть файл

@ -0,0 +1,87 @@
---
AccessModifierOffset: -1
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: false
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: WebKit
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, ]
IncludeCategories:
- Regex: '^<.*\.h(pp)?>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: true
IndentWidth: 2
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...

Просмотреть файл

@ -97,8 +97,8 @@ RCT_EXTERN NSString *RCTBridgeModuleNameForClass(Class bridgeModuleClass);
* Experimental.
* Check/set if JSI-bound NativeModule is enabled. By default it's off.
*/
RCT_EXTERN BOOL RCTJSINativeModuleEnabled(void);
RCT_EXTERN void RCTEnableJSINativeModule(BOOL enabled);
RCT_EXTERN BOOL RCTTurboModuleEnabled(void);
RCT_EXTERN void RCTEnableTurboModule(BOOL enabled);
/**
* Async batched bridge used to communicate with the JavaScript application.
@ -151,8 +151,12 @@ RCT_EXTERN void RCTEnableJSINativeModule(BOOL enabled);
* lazily instantiated, so calling these methods for the first time with a given
* module name/class may cause the class to be sychronously instantiated,
* potentially blocking both the calling thread and main thread for a short time.
*
* Note: This method does NOT lazily load the particular module if it's not yet loaded.
*/
- (id)moduleForName:(NSString *)moduleName;
- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad;
// Note: This method lazily load the module as necessary.
- (id)moduleForClass:(Class)moduleClass;
/**

Просмотреть файл

@ -85,14 +85,14 @@ NSString *RCTBridgeModuleNameForClass(Class cls)
return RCTDropReactPrefixes(name);
}
static BOOL jsiNativeModuleEnabled = NO;
BOOL RCTJSINativeModuleEnabled(void)
static BOOL turboModuleEnabled = NO;
BOOL RCTTurboModuleEnabled(void)
{
return jsiNativeModuleEnabled;
return turboModuleEnabled;
}
void RCTEnableJSINativeModule(BOOL enabled) {
jsiNativeModuleEnabled = enabled;
void RCTEnableTurboModule(BOOL enabled) {
turboModuleEnabled = enabled;
}
#if RCT_DEBUG
@ -241,6 +241,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
return [self.batchedBridge moduleForName:moduleName];
}
- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
{
return [self.batchedBridge moduleForName:moduleName lazilyLoadIfNecessary:lazilyLoad];
}
- (id)moduleForClass:(Class)moduleClass
{
id module = [self.batchedBridge moduleForClass:moduleClass];

Просмотреть файл

@ -301,7 +301,7 @@ RCT_EXTERN void RCTRegisterModule(Class); \
* for the lifetime of the bridge, so it is not suitable for returning dynamic values, but may be used for long-lived
* values such as session keys, that are regenerated only as part of a reload of the entire React application.
*
* If you implement this method and do not implement `requiresMainThreadSetup`, you will trigger deprecated logic
* If you implement this method and do not implement `requiresMainQueueSetup`, you will trigger deprecated logic
* that eagerly initializes your module on bridge startup. In the future, this behaviour will be changed to default
* to initializing lazily, and even modules with constants will be initialized lazily.
*/
@ -324,9 +324,9 @@ RCT_EXTERN void RCTRegisterModule(Class); \
/**
* Experimental.
* A protocol to declare that a class supports JSI-bound NativeModule.
* A protocol to declare that a class supports TurboModule.
* This may be removed in the future.
*/
@protocol RCTJSINativeModule <NSObject>
@protocol RCTTurboModule <NSObject>
@end

Просмотреть файл

@ -439,6 +439,30 @@ struct RCTInstanceCallback : public InstanceCallback {
return _moduleDataByName[moduleName].instance;
}
- (id)moduleForName:(NSString *)moduleName lazilyLoadIfNecessary:(BOOL)lazilyLoad
{
if (!lazilyLoad) {
return [self moduleForName:moduleName];
}
RCTModuleData *moduleData = _moduleDataByName[moduleName];
if (moduleData) {
return moduleData.instance;
}
// Module may not be loaded yet, so attempt to force load it here.
const BOOL result = [self.delegate respondsToSelector:@selector(bridge:didNotFindModule:)] &&
[self.delegate bridge:self didNotFindModule:moduleName];
if (result) {
// Try again.
moduleData = _moduleDataByName[moduleName];
} else {
RCTLogError(@"Unable to find module for %@", moduleName);
}
return moduleData.instance;
}
- (BOOL)moduleIsInitialized:(Class)moduleClass
{
return _moduleDataByName[RCTBridgeModuleNameForClass(moduleClass)].hasInstance;
@ -446,17 +470,7 @@ struct RCTInstanceCallback : public InstanceCallback {
- (id)moduleForClass:(Class)moduleClass
{
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
RCTModuleData *moduleData = _moduleDataByName[moduleName];
if (moduleData) {
return moduleData.instance;
}
// Module may not be loaded yet, so attempt to force load it here.
RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)], @"Asking for a NativeModule that doesn't conform to RCTBridgeModule: %@", NSStringFromClass(moduleClass));
[self registerAdditionalModuleClasses:@[moduleClass]];
return _moduleDataByName[moduleName].instance;
return [self moduleForName:RCTBridgeModuleNameForClass(moduleClass) lazilyLoadIfNecessary:YES];
}
- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistryUnlocked
@ -547,7 +561,7 @@ struct RCTInstanceCallback : public InstanceCallback {
NSArray *moduleClassesCopy = [moduleClasses copy];
NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray arrayWithCapacity:moduleClassesCopy.count];
for (Class moduleClass in moduleClassesCopy) {
if (RCTJSINativeModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTJSINativeModule)]) {
if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
continue;
}
NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
@ -652,7 +666,7 @@ struct RCTInstanceCallback : public InstanceCallback {
// we must use the names provided by the delegate method here.
for (NSString *moduleName in moduleClasses) {
Class moduleClass = moduleClasses[moduleName];
if (RCTJSINativeModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTJSINativeModule)]) {
if (RCTTurboModuleEnabled() && [moduleClass conformsToProtocol:@protocol(RCTTurboModule)]) {
continue;
}

Просмотреть файл

@ -73,7 +73,7 @@ using namespace facebook::react;
_imageLocalData = std::static_pointer_cast<const ImageLocalData>(localData);
assert(_imageLocalData);
auto future = _imageLocalData->getImageRequest().getResponseFuture();
future.via(&MainQueueExecutor::instance()).then([self](ImageResponse &&imageResponse) {
future.via(&MainQueueExecutor::instance()).thenValue([self](ImageResponse &&imageResponse) {
self.image = (__bridge UIImage *)imageResponse.getImage().get();
});
}

Просмотреть файл

@ -130,7 +130,7 @@ static BOOL AnyTouchesChanged(NSSet<UITouch *> *touches) {
template<typename PointerT>
struct PointerHasher {
constexpr std::size_t operator()(const PointerT &value) const {
return reinterpret_cast<size_t>(&value);
return reinterpret_cast<size_t>(value);
}
};
@ -196,29 +196,39 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
- (void)_updateTouches:(NSSet<UITouch *> *)touches
{
for (UITouch *touch in touches) {
UpdateActiveTouchWithUITouch(_activeTouches[touch], touch, _rootComponentView);
UpdateActiveTouchWithUITouch(_activeTouches.at(touch), touch, _rootComponentView);
}
}
- (void)_unregisterTouches:(NSSet<UITouch *> *)touches
{
for (UITouch *touch in touches) {
const auto &activeTouch = _activeTouches[touch];
const auto &activeTouch = _activeTouches.at(touch);
_identifierPool.enqueue(activeTouch.touch.identifier);
_activeTouches.erase(touch);
}
}
- (void)_dispatchTouches:(NSSet<UITouch *> *)touches eventType:(RCTTouchEventType)eventType
- (std::vector<ActiveTouch>)_activeTouchesFromTouches:(NSSet<UITouch *> *)touches
{
std::vector<ActiveTouch> activeTouches;
activeTouches.reserve(touches.count);
for (UITouch *touch in touches) {
activeTouches.push_back(_activeTouches.at(touch));
}
return activeTouches;
}
- (void)_dispatchActiveTouches:(std::vector<ActiveTouch>)activeTouches eventType:(RCTTouchEventType)eventType
{
TouchEvent event = {};
std::unordered_set<ActiveTouch, ActiveTouch::Hasher, ActiveTouch::Comparator> changedActiveTouches = {};
std::unordered_set<SharedTouchEventEmitter> uniqueEventEmitter = {};
BOOL isEndishEventType = eventType == RCTTouchEventTypeTouchEnd || eventType == RCTTouchEventTypeTouchCancel;
for (UITouch *touch in touches) {
const auto &activeTouch = _activeTouches[touch];
for (const auto &activeTouch : activeTouches) {
if (!activeTouch.eventEmitter) {
continue;
}
@ -276,7 +286,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesBegan:touches withEvent:event];
[self _registerTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchStart];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchStart];
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateBegan;
@ -290,7 +301,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesMoved:touches withEvent:event];
[self _updateTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchMove];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchMove];
self.state = UIGestureRecognizerStateChanged;
}
@ -300,7 +312,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesEnded:touches withEvent:event];
[self _updateTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchEnd];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchEnd];
[self _unregisterTouches:touches];
if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
@ -315,7 +328,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
[super touchesCancelled:touches withEvent:event];
[self _updateTouches:touches];
[self _dispatchTouches:touches eventType:RCTTouchEventTypeTouchCancel];
[self _dispatchActiveTouches:[self _activeTouchesFromTouches:touches]
eventType:RCTTouchEventTypeTouchCancel];
[self _unregisterTouches:touches];
if (AllTouchesAreCancelledOrEnded(event.allTouches)) {
@ -327,10 +341,23 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithTarget:(id)target action:(SEL)action
- (void)reset
{
// Technically, `_activeTouches` must be already empty at this point,
// but just to be sure, we clear it explicitly.
_activeTouches.clear();
_identifierPool.reset();
[super reset];
if (_activeTouches.size() != 0) {
std::vector<ActiveTouch> activeTouches;
activeTouches.reserve(_activeTouches.size());
for (auto const &pair : _activeTouches) {
activeTouches.push_back(pair.second);
}
[self _dispatchActiveTouches:activeTouches
eventType:RCTTouchEventTypeTouchCancel];
// Force-unregistering all the touches.
_activeTouches.clear();
_identifierPool.reset();
}
}
- (BOOL)canPreventGestureRecognizer:(__unused UIGestureRecognizer *)preventedGestureRecognizer

Просмотреть файл

@ -49,7 +49,8 @@
_rootTag = [RCTAllocateRootViewTag() integerValue];
_minimumSize = CGSizeZero;
_maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
// FIXME: Replace with `_maximumSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);`.
_maximumSize = RCTScreenSize();
_touchHandler = [RCTSurfaceTouchHandler new];

Просмотреть файл

@ -488,6 +488,7 @@ static NSDictionary *deviceOrientationEventBody(UIDeviceOrientation orientation)
UIUserInterfaceLayoutDirection layoutDirection;
BOOL isNew;
BOOL parentIsNew;
RCTDisplayType displayType;
} RCTFrameData;
// Construct arrays then hand off to main thread
@ -505,6 +506,7 @@ static NSDictionary *deviceOrientationEventBody(UIDeviceOrientation orientation)
layoutMetrics.layoutDirection,
shadowView.isNewView,
shadowView.superview.isNewView,
layoutMetrics.displayType
};
}
}
@ -566,6 +568,7 @@ static NSDictionary *deviceOrientationEventBody(UIDeviceOrientation orientation)
RCTLayoutAnimation *updatingLayoutAnimation = isNew ? nil : layoutAnimationGroup.updatingLayoutAnimation;
BOOL shouldAnimateCreation = isNew && !frameData.parentIsNew;
RCTLayoutAnimation *creatingLayoutAnimation = shouldAnimateCreation ? layoutAnimationGroup.creatingLayoutAnimation : nil;
BOOL isHidden = frameData.displayType == RCTDisplayTypeNone;
void (^completion)(BOOL) = ^(BOOL finished) {
completionsCalled++;
@ -581,6 +584,10 @@ static NSDictionary *deviceOrientationEventBody(UIDeviceOrientation orientation)
if (view.reactLayoutDirection != layoutDirection) {
view.reactLayoutDirection = layoutDirection;
}
if (view.isHidden != isHidden) {
view.hidden = isHidden;
}
if (creatingLayoutAnimation) {

Просмотреть файл

@ -36,6 +36,7 @@ shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
@property (nonatomic, assign) UIEdgeInsets contentInset;
@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets;
+ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential;
- (void)postMessage:(NSString *)message;
- (void)injectJavaScript:(NSString *)script;
- (void)goForward;

Просмотреть файл

@ -10,6 +10,8 @@
#import "RCTAutoInsetsProtocol.h"
static NSString *const MessageHanderName = @"ReactNative";
static NSURLCredential* clientAuthenticationCredential;
@interface RCTWKWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageHandler, UIScrollViewDelegate, RCTAutoInsetsProtocol>
@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
@ -310,6 +312,25 @@ static NSString *const MessageHanderName = @"ReactNative";
[self setBackgroundColor: _savedBackgroundColor];
}
+ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential {
clientAuthenticationCredential = credential;
}
- (void) webView:(WKWebView *)webView
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable))completionHandler
{
if (!clientAuthenticationCredential) {
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
return;
}
if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential);
} else {
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}
}
- (void)evaluateJS:(NSString *)js
thenCall: (void (^)(NSString*)) callback
{

Просмотреть файл

@ -162,7 +162,7 @@ task prepareJSC(dependsOn: dependenciesPath ? [] : [downloadJSCHeaders]) << {
copy {
from zipTree(configurations.compile.fileCollection { dep -> dep.name == 'android-jsc' }.singleFile)
from dependenciesPath ? "$dependenciesPath/jsc-headers" : {downloadJSCHeaders.dest}
from 'src/main/jni/third-party/jsc/Android.mk'
from 'src/main/jni/third-party/jsc'
include 'jni/**/*.so', '*.h', 'Android.mk'
filesMatching('*.h', { fname -> fname.path = "JavaScriptCore/${fname.path}"})
into "$thirdPartyNdkDir/jsc";
@ -289,7 +289,7 @@ android {
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir "$buildDir/react-ndk/exported"
jniLibs.srcDirs = ["$buildDir/react-ndk/exported", 'src/main/jni/third-party/jsc/jni']
res.srcDirs = ['src/main/res/devsupport', 'src/main/res/shell', 'src/main/res/views/modal', 'src/main/res/views/uimanager']
java {
srcDirs = ['src/main/java', 'src/main/libraries/soloader/java', 'src/main/jni/first-party/fb/jni/java']
@ -324,7 +324,7 @@ dependencies {
api "com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}"
api "com.squareup.okhttp3:okhttp-urlconnection:${OKHTTP_VERSION}"
api 'com.squareup.okio:okio:1.14.0'
compile project(':android-jsc')
compile 'org.webkit:android-jsc:r174650'
testImplementation "junit:junit:${JUNIT_VERSION}"
testImplementation "org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}"

Просмотреть файл

@ -0,0 +1,104 @@
package com.facebook.react.tests.core;
import static org.fest.assertions.api.Assertions.assertThat;
import android.support.test.runner.AndroidJUnit4;
import com.facebook.react.bridge.UnexpectedNativeTypeException;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class WritableNativeMapTest {
private WritableNativeMap mMap;
@Before
public void setup() {
mMap = new WritableNativeMap();
mMap.putBoolean("boolean", true);
mMap.putDouble("double", 1.2);
mMap.putInt("int", 1);
mMap.putString("string", "abc");
mMap.putMap("map", new WritableNativeMap());
mMap.putArray("array", new WritableNativeArray());
mMap.putBoolean("dvacca", true);
mMap.setUseNativeAccessor(true);
}
@Test
public void testBoolean() {
assertThat(mMap.getBoolean("boolean")).isEqualTo(true);
}
@Test(expected = UnexpectedNativeTypeException.class)
public void testBooleanInvalidType() {
mMap.getBoolean("string");
}
@Test
public void testDouble() {
assertThat(mMap.getDouble("double")).isEqualTo(1.2);
}
@Test(expected = UnexpectedNativeTypeException.class)
public void testDoubleInvalidType() {
mMap.getDouble("string");
}
@Test
public void testInt() {
assertThat(mMap.getInt("int")).isEqualTo(1);
}
@Test(expected = UnexpectedNativeTypeException.class)
public void testIntInvalidType() {
mMap.getInt("string");
}
@Test
public void testString() {
assertThat(mMap.getString("string")).isEqualTo("abc");
}
@Test(expected = UnexpectedNativeTypeException.class)
public void testStringInvalidType() {
mMap.getString("int");
}
@Test
public void testMap() {
assertThat(mMap.getMap("map")).isNotNull();
}
@Test(expected = UnexpectedNativeTypeException.class)
public void testMapInvalidType() {
mMap.getMap("string");
}
@Test
public void testArray() {
assertThat(mMap.getArray("array")).isNotNull();
}
@Test(expected = UnexpectedNativeTypeException.class)
public void testArrayInvalidType() {
mMap.getArray("string");
}
@Ignore("Needs to be implemented")
@Test
public void testErrorMessageContainsKey() {
String key = "fkg";
try {
mMap.getString(key);
Assert.fail("Expected an UnexpectedNativeTypeException to be thrown");
} catch (UnexpectedNativeTypeException e) {
assertThat(e.getMessage()).contains(key);
}
}
}

Просмотреть файл

@ -325,7 +325,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
// shared under the hood.
// See https://github.com/square/okhttp/wiki/Recipes#per-call-configuration for more information
if (timeout != mClient.connectTimeoutMillis()) {
clientBuilder.readTimeout(timeout, TimeUnit.MILLISECONDS);
clientBuilder.connectTimeout(timeout, TimeUnit.MILLISECONDS);
}
OkHttpClient client = clientBuilder.build();

Просмотреть файл

@ -7,6 +7,7 @@ package com.facebook.react.modules.systeminfo;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
@ -84,7 +85,7 @@ public class AndroidInfoHelpers {
Runtime.getRuntime().exec(new String[] {"/system/bin/getprop", METRO_HOST_PROP_NAME});
reader =
new BufferedReader(
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
new InputStreamReader(process.getInputStream(), Charset.forName("UTF-8")));
String lastLine = "";
String line;

Просмотреть файл

@ -147,6 +147,11 @@ public final class WebSocketModule extends ReactContextBaseJavaModule {
sendEvent("websocketOpen", params);
}
@Override
public void onClosing(WebSocket websocket, int code, String reason) {
websocket.close(code, reason);
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
WritableMap params = Arguments.createMap();

Просмотреть файл

@ -562,6 +562,11 @@ public class NativeViewHierarchyManager {
*/
protected synchronized void dropView(View view) {
UiThreadUtil.assertOnUiThread();
if (mTagsToViewManagers.get(view.getId()) == null) {
// This view has already been dropped (likely due to a threading issue caused by async js
// execution). Ignore this drop operation.
return;
}
if (!mRootTags.get(view.getId())) {
// For non-root views we notify viewmanager with {@link ViewManager#onDropInstance}
resolveViewManager(view.getId()).onDropViewInstance(view);

Просмотреть файл

@ -94,8 +94,6 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
void removeAndDisposeAllChildren();
@Nullable ReactStylesDiffMap getNewProps();
/**
* This method will be called by {@link UIManagerModule} once per batch, before calculating
* layout. Will be only called for nodes that are marked as updated with {@link #markUpdated()} or
@ -348,12 +346,4 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
boolean isMeasureDefined();
void dispose();
/**
* @return an immutable {@link List<ReactShadowNode>} containing the children of this
* {@link ReactShadowNode}.
*/
List<ReactShadowNode> getChildrenList();
void updateScreenLayout(ReactShadowNode prevNode);
}

Просмотреть файл

@ -6,12 +6,7 @@
*/
package com.facebook.react.uimanager;
import static java.lang.System.arraycopy;
import com.facebook.debug.holder.PrinterHolder;
import com.facebook.debug.tags.ReactDebugOverlayTags;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaBaselineFunction;
@ -30,8 +25,6 @@ import com.facebook.yoga.YogaValue;
import com.facebook.yoga.YogaWrap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
/**
@ -60,8 +53,6 @@ import javax.annotation.Nullable;
@ReactPropertyHolder
public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl> {
private static final boolean DEBUG = ReactBuildConfig.DEBUG || PrinterHolder.getPrinter().shouldDisplayLogMessage(ReactDebugOverlayTags.FABRIC_UI_MANAGER);
private static final String TAG = ReactShadowNodeImpl.class.getSimpleName();
private static final YogaConfig sYogaConfig;
static {
@ -90,12 +81,6 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
private final float[] mPadding = new float[Spacing.ALL + 1];
private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1];
private YogaNode mYogaNode;
private int mGenerationDebugInformation = 1;
private ReactShadowNode mOriginalReactShadowNode = null;
private @Nullable ReactStylesDiffMap mNewProps;
private long mInstanceHandle;
private boolean mIsSealed = false;
public ReactShadowNodeImpl() {
mDefaultPadding = new Spacing(0);
@ -109,32 +94,6 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
}
}
protected ReactShadowNodeImpl(ReactShadowNodeImpl original) {
mReactTag = original.mReactTag;
mRootTag = original.mRootTag;
mViewClassName = original.mViewClassName;
mThemedContext = original.mThemedContext;
mShouldNotifyOnLayout = original.mShouldNotifyOnLayout;
mIsLayoutOnly = original.mIsLayoutOnly;
mNativeParent = original.mNativeParent;
mDefaultPadding = new Spacing(original.mDefaultPadding);
// Cloned nodes should be always updated.
mNodeUpdated = true;
// "cached" screen coordinates are not cloned because FabricJS not always clone the last
// ReactShadowNode that was rendered in the screen.
mScreenX = 0;
mScreenY = 0;
mScreenWidth = 0;
mScreenHeight = 0;
mGenerationDebugInformation = original.mGenerationDebugInformation + 1;
arraycopy(original.mPadding, 0, mPadding, 0, original.mPadding.length);
arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length);
mNewProps = null;
mParent = null;
mOriginalReactShadowNode = original;
mIsSealed = false;
}
/**
* Nodes that return {@code true} will be treated as "virtual" nodes. That is, nodes that are not
* mapped into native views (e.g. nested text node). By default this method returns {@code false}.
@ -339,12 +298,6 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
// no-op
}
@Override
@Nullable
public ReactStylesDiffMap getNewProps() {
return mNewProps;
}
/**
* Called after layout step at the end of the UI batch from {@link UIManagerModule}. May be used
* to enqueue additional ui operations for the native view. Will only be called on nodes marked as
@ -976,7 +929,7 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
}
result.append("<").append(getClass().getSimpleName()).append(" view='").append(getViewClass())
.append("' tag=").append(getReactTag()).append(" gen=").append(mGenerationDebugInformation);
.append("' tag=").append(getReactTag());
if (mYogaNode != null) {
result.append(" layout='x:").append(getScreenX())
.append(" y:").append(getScreenY()).append(" w:").append(getLayoutWidth()).append(" h:")
@ -1003,17 +956,4 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
}
}
@Nullable
@Override
public List<ReactShadowNode> getChildrenList() {
return mChildren == null ? null : Collections.<ReactShadowNode>unmodifiableList(mChildren);
}
@Override
public void updateScreenLayout(ReactShadowNode prevNode) {
mScreenHeight = prevNode.getScreenHeight();
mScreenWidth = prevNode.getScreenWidth();
mScreenX = prevNode.getScreenX();
mScreenY = prevNode.getScreenY();
}
}

Просмотреть файл

@ -9,6 +9,7 @@ package com.facebook.react.uimanager;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.View;
import com.facebook.react.common.SingleThreadAsserter;
/**
@ -36,6 +37,11 @@ public class ShadowNodeRegistry {
public void removeRootNode(int tag) {
mThreadAsserter.assertNow();
if (tag == View.NO_ID) {
// This root node has already been removed (likely due to a threading issue caused by async js
// execution). Ignore this root removal.
return;
}
if (!mRootTags.get(tag)) {
throw new IllegalViewOperationException(
"View with tag " + tag + " is not registered as a root view");

Просмотреть файл

@ -18,6 +18,7 @@ import com.facebook.react.touch.ReactInterceptingViewGroup;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
import com.facebook.yoga.YogaMeasureMode;
import java.util.Map;
import javax.annotation.Nullable;
@ -218,9 +219,9 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
ReadableNativeMap localData,
ReadableNativeMap props,
float width,
int widthMode,
YogaMeasureMode widthMode,
float height,
int heightMode) {
YogaMeasureMode heightMode) {
return null;
}
}

Просмотреть файл

@ -8,7 +8,6 @@
package com.facebook.react.uimanager.events;
import android.view.MotionEvent;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;

Просмотреть файл

@ -439,7 +439,7 @@ public class ReactImageView extends GenericDraweeView {
hierarchy.setActualImageScaleType(mScaleType);
if (mDefaultImageDrawable != null) {
hierarchy.setPlaceholderImage(mDefaultImageDrawable, ScalingUtils.ScaleType.CENTER);
hierarchy.setPlaceholderImage(mDefaultImageDrawable, mScaleType);
}
if (mLoadingImageDrawable != null) {

Просмотреть файл

@ -309,8 +309,18 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
@Override
public void fling(int velocityY) {
// Workaround.
// On Android P if a ScrollView is inverted, we will get a wrong sign for
// velocityY (see https://issuetracker.google.com/issues/112385925).
// At the same time, mOnScrollDispatchHelper tracks the correct velocity direction.
//
// Hence, we can use the absolute value from whatever the OS gives
// us and use the sign of what mOnScrollDispatchHelper has tracked.
final int correctedVelocityY = (int)(Math.abs(velocityY) * Math.signum(mOnScrollDispatchHelper.getYFlingVelocity()));
if (mPagingEnabled) {
flingAndSnap(velocityY);
flingAndSnap(correctedVelocityY);
} else if (mScroller != null) {
// FB SCROLLVIEW CHANGE
@ -326,7 +336,7 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
getScrollX(), // startX
getScrollY(), // startY
0, // velocityX
velocityY, // velocityY
correctedVelocityY, // velocityY
0, // minX
0, // maxX
0, // minY
@ -339,9 +349,9 @@ public class ReactScrollView extends ScrollView implements ReactClippingViewGrou
// END FB SCROLLVIEW CHANGE
} else {
super.fling(velocityY);
super.fling(correctedVelocityY);
}
handlePostTouchScrolling(0, velocityY);
handlePostTouchScrolling(0, correctedVelocityY);
}
private void enableFpsListener() {

Просмотреть файл

@ -1,13 +1,11 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.facebook.react.views.text;
import android.graphics.Rect;
import android.os.Build;
import android.text.BoringLayout;
import android.text.Layout;
@ -15,15 +13,12 @@ import android.text.Spannable;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.widget.TextView;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.ReactShadowNodeImpl;
import com.facebook.react.uimanager.Spacing;
import com.facebook.react.uimanager.UIViewOperationQueue;
import com.facebook.react.uimanager.annotations.ReactProp;
@ -62,16 +57,17 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
YogaMeasureMode widthMode,
float height,
YogaMeasureMode heightMode) {
// TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic)
TextPaint textPaint = sTextPaintInstance;
textPaint.setTextSize(mFontSize != UNSET ? mFontSize : getDefaultFontSize());
Layout layout;
Spanned text = Assertions.assertNotNull(
mPreparedSpannableText,
"Spannable element has not been prepared in onBeforeLayout");
Spanned text =
Assertions.assertNotNull(
mPreparedSpannableText,
"Spannable element has not been prepared in onBeforeLayout");
BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint);
float desiredWidth = boring == null ?
Layout.getDesiredWidth(text, textPaint) : Float.NaN;
float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN;
// technically, width should never be negative, but there is currently a bug in
boolean unconstrainedWidth = widthMode == YogaMeasureMode.UNDEFINED || width < 0;
@ -89,70 +85,64 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
break;
}
if (boring == null &&
(unconstrainedWidth ||
(!YogaConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
if (boring == null
&& (unconstrainedWidth
|| (!YogaConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
// Is used when the width is not known and the text is not boring, ie. if it contains
// unicode characters.
int hintWidth = (int) Math.ceil(desiredWidth);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
layout = new StaticLayout(
text,
textPaint,
hintWidth,
alignment,
1.f,
0.f,
mIncludeFontPadding);
layout =
new StaticLayout(
text, textPaint, hintWidth, alignment, 1.f, 0.f, mIncludeFontPadding);
} else {
layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, hintWidth)
.setAlignment(alignment)
.setLineSpacing(0.f, 1.f)
.setIncludePad(mIncludeFontPadding)
.setBreakStrategy(mTextBreakStrategy)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
layout =
StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, hintWidth)
.setAlignment(alignment)
.setLineSpacing(0.f, 1.f)
.setIncludePad(mIncludeFontPadding)
.setBreakStrategy(mTextBreakStrategy)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
}
} else if (boring != null && (unconstrainedWidth || boring.width <= width)) {
// Is used for single-line, boring text when the width is either unknown or bigger
// than the width of the text.
layout = BoringLayout.make(
text,
textPaint,
boring.width,
alignment,
1.f,
0.f,
boring,
mIncludeFontPadding);
layout =
BoringLayout.make(
text,
textPaint,
boring.width,
alignment,
1.f,
0.f,
boring,
mIncludeFontPadding);
} else {
// Is used for multiline, boring text and the width is known.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
layout = new StaticLayout(
text,
textPaint,
(int) width,
alignment,
1.f,
0.f,
mIncludeFontPadding);
layout =
new StaticLayout(
text, textPaint, (int) width, alignment, 1.f, 0.f, mIncludeFontPadding);
} else {
layout = StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width)
.setAlignment(alignment)
.setLineSpacing(0.f, 1.f)
.setIncludePad(mIncludeFontPadding)
.setBreakStrategy(mTextBreakStrategy)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
layout =
StaticLayout.Builder.obtain(text, 0, text.length(), textPaint, (int) width)
.setAlignment(alignment)
.setLineSpacing(0.f, 1.f)
.setIncludePad(mIncludeFontPadding)
.setBreakStrategy(mTextBreakStrategy)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
}
}
if (mShouldNotifyOnTextLayout) {
WritableArray lines =
FontMetricsUtil.getFontMetrics(text, layout, sTextPaintInstance, getThemedContext());
FontMetricsUtil.getFontMetrics(
text, layout, sTextPaintInstance, getThemedContext());
WritableMap event = Arguments.createMap();
event.putArray("lines", lines);
getThemedContext()
@ -161,7 +151,8 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
}
if (mNumberOfLines != UNSET && mNumberOfLines < layout.getLineCount()) {
return YogaMeasureOutput.make(layout.getWidth(), layout.getLineBottom(mNumberOfLines - 1));
return YogaMeasureOutput.make(
layout.getWidth(), layout.getLineBottom(mNumberOfLines - 1));
} else {
return YogaMeasureOutput.make(layout.getWidth(), layout.getHeight());
}
@ -215,17 +206,16 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
if (mPreparedSpannableText != null) {
ReactTextUpdate reactTextUpdate =
new ReactTextUpdate(
mPreparedSpannableText,
UNSET,
mContainsImages,
getPadding(Spacing.START),
getPadding(Spacing.TOP),
getPadding(Spacing.END),
getPadding(Spacing.BOTTOM),
getTextAlign(),
mTextBreakStrategy
);
new ReactTextUpdate(
mPreparedSpannableText,
UNSET,
mContainsImages,
getPadding(Spacing.START),
getPadding(Spacing.TOP),
getPadding(Spacing.END),
getPadding(Spacing.BOTTOM),
getTextAlign(),
mTextBreakStrategy);
uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate);
}
}

Просмотреть файл

@ -9,18 +9,18 @@ package com.facebook.react.views.text;
import android.text.Layout;
import android.text.Spannable;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.yoga.YogaMeasureMode;
import java.util.Map;
import javax.annotation.Nullable;
import com.facebook.yoga.YogaMeasureMode;
/**
* Concrete class for {@link ReactTextAnchorViewManager} which represents view managers of anchor
@ -109,18 +109,17 @@ public class ReactTextViewManager
ReadableNativeMap localData,
ReadableNativeMap props,
float width,
int widthMode,
YogaMeasureMode widthMode,
float height,
int heightMode) {
YogaMeasureMode heightMode) {
// TODO: should widthMode and heightMode be a YogaMeasureMode?
return TextLayoutManager.measureText(context,
view,
localData,
props,
width,
YogaMeasureMode.fromInt(widthMode),
widthMode,
height,
YogaMeasureMode.fromInt(heightMode));
heightMode);
}
}

Просмотреть файл

@ -384,33 +384,40 @@ public class TextAttributeProps {
: -1;
}
//TODO remove this from here
//TODO T31905686 remove this from here and add support to RTL
private YogaDirection getLayoutDirection() {
return YogaDirection.LTR;
}
public float getBottomPadding() {
// TODO convert into constants
return getFloatProp("bottomPadding", 0f);
return getPaddingProp(ViewProps.PADDING_BOTTOM);
}
public float getLeftPadding() {
return getFloatProp("leftPadding", 0f);
return getPaddingProp(ViewProps.PADDING_LEFT);
}
public float getStartPadding() {
return getFloatProp("startPadding", 0f);
return getPaddingProp(ViewProps.PADDING_START);
}
public float getEndPadding() {
return getFloatProp("endPadding", 0f);
return getPaddingProp(ViewProps.PADDING_END);
}
public float getTopPadding() {
return getFloatProp("topPadding", 0f);
return getPaddingProp(ViewProps.PADDING_TOP);
}
public float getRightPadding() {
return getFloatProp("rightPadding", 0f);
return getPaddingProp(ViewProps.PADDING_RIGHT);
}
private float getPaddingProp(String paddingType) {
if (mProps.hasKey(ViewProps.PADDING)) {
return PixelUtil.toPixelFromDIP(getFloatProp(ViewProps.PADDING, 0f));
}
return PixelUtil.toPixelFromDIP(getFloatProp(paddingType, 0f));
}
}

Просмотреть файл

@ -29,8 +29,10 @@ import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.ViewDefaults;
import com.facebook.yoga.YogaConstants;
import com.facebook.yoga.YogaMeasureMode;
import java.awt.font.TextAttribute;
import java.util.ArrayList;
import java.util.List;
@ -95,11 +97,9 @@ public class TextLayoutManager {
new CustomLetterSpacingSpan(textAttributes.mLetterSpacing)));
}
}
if (textAttributes.mFontSize != UNSET) {
ops.add(
new SetSpanOperation(
start, end, new AbsoluteSizeSpan((int) (textAttributes.mFontSize))));
}
ops.add(
new SetSpanOperation(
start, end, new AbsoluteSizeSpan(textAttributes.mFontSize)));
if (textAttributes.mFontStyle != UNSET
|| textAttributes.mFontWeight != UNSET
|| textAttributes.mFontFamily != null) {
@ -163,23 +163,14 @@ public class TextLayoutManager {
buildSpannedFromShadowNode(context, fragments, sb, ops);
// TODO: add support for AllowScaling in C++
// if (textShadowNode.mFontSize == UNSET) {
// int defaultFontSize =
// textShadowNode.mAllowFontScaling
// ? (int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP))
// : (int) Math.ceil(PixelUtil.toPixelFromDIP(ViewDefaults.FONT_SIZE_SP));
//
// ops.add(new SetSpanOperation(0, sb.length(), new AbsoluteSizeSpan(defaultFontSize)));
// }
//
// TODO T31905686: add support for inline Images
// textShadowNode.mContainsImages = false;
// textShadowNode.mHeightOfTallestInlineImage = Float.NaN;
// While setting the Spans on the final text, we also check whether any of them are images.
int priority = 0;
for (SetSpanOperation op : ops) {
// TODO: add support for TextInlineImage in C++
// TODO T31905686: add support for TextInlineImage in C++
// if (op.what instanceof TextInlineImageSpan) {
// int height = ((TextInlineImageSpan) op.what).getHeight();
// textShadowNode.mContainsImages = true;

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
@ -8,6 +8,7 @@
package com.facebook.yoga;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.soloader.SoLoader;
@DoNotStrip
public class YogaConfig {
@ -15,7 +16,7 @@ public class YogaConfig {
public static int SPACING_TYPE = 1;
static {
YogaJNI.init();
SoLoader.loadLibrary("yoga");
}
long mNativePointer;

Просмотреть файл

@ -35,4 +35,8 @@ public class YogaConstants {
public static boolean isUndefined(YogaValue value) {
return value.unit == YogaUnit.UNDEFINED;
}
public static float getUndefined() {
return UNDEFINED;
}
}

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,32 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*
*/
package com.facebook.yoga;
import com.facebook.soloader.SoLoader;
public class YogaJNI {
private static boolean isInitialized = false;
// Known constants. 1-3 used in previous experiments. Do not reuse.
public static int JNI_FAST_CALLS = 4;
// set before loading any other Yoga code
public static boolean useFastCall = false;
private static native void jni_bindNativeMethods(boolean useFastCall);
static synchronized boolean init() {
if (!isInitialized) {
isInitialized = true;
SoLoader.loadLibrary("yoga");
jni_bindNativeMethods(useFastCall);
return true;
}
return false;
}
}

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
@ -8,6 +8,7 @@
package com.facebook.yoga;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.soloader.SoLoader;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
@ -16,7 +17,7 @@ import javax.annotation.Nullable;
public class YogaNode implements Cloneable {
static {
YogaJNI.init();
SoLoader.loadLibrary("yoga");
}
/**
@ -159,6 +160,7 @@ public class YogaNode implements Cloneable {
}
private static native void jni_YGNodeInsertChild(long nativePointer, long childPointer, int index);
public void addChildAt(YogaNode child, int i) {
if (child.mOwner != null) {
throw new IllegalStateException("Child already has a parent, it must be removed first.");
@ -183,6 +185,18 @@ public class YogaNode implements Cloneable {
jni_YGNodeInsertSharedChild(mNativePointer, child.mNativePointer, i);
}
private static native void jni_YGNodeSetIsReferenceBaseline(long nativePointer, boolean isReferenceBaseline);
public void setIsReferenceBaseline(boolean isReferenceBaseline) {
jni_YGNodeSetIsReferenceBaseline(mNativePointer, isReferenceBaseline);
}
private static native boolean jni_YGNodeIsReferenceBaseline(long nativePointer);
public boolean isReferenceBaseline() {
return jni_YGNodeIsReferenceBaseline(mNativePointer);
}
private static native void jni_YGNodeSetOwner(long nativePointer, long newOwnerNativePointer);
private native long jni_YGNodeClone(long nativePointer, Object newNode);

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
* Copyright (c) Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.

Просмотреть файл

@ -371,6 +371,17 @@ void jni_YGNodeRemoveChild(jlong nativePointer, jlong childPointer) {
_jlong2YGNodeRef(nativePointer), _jlong2YGNodeRef(childPointer));
}
void jni_YGNodeSetIsReferenceBaseline(
jlong nativePointer,
jboolean isReferenceBaseline) {
YGNodeSetIsReferenceBaseline(
_jlong2YGNodeRef(nativePointer), isReferenceBaseline);
}
jboolean jni_YGNodeIsReferenceBaseline(jlong nativePointer) {
return YGNodeIsReferenceBaseline(_jlong2YGNodeRef(nativePointer));
}
void jni_YGNodeCalculateLayout(
alias_ref<jclass>,
jlong nativePointer,
@ -647,130 +658,112 @@ jint jni_YGNodeGetInstanceCount() {
}
#define YGMakeNativeMethod(name) makeNativeMethod(#name, name)
#define YGRealMakeCriticalNativeMethod(name) \
makeCriticalNativeMethod(#name, name)
#define YGWrapCriticalNativeMethodForRegularCall(name) \
makeNativeMethod( \
#name, \
::facebook::jni::detail::CriticalMethod<decltype(&name)>::call<&name>)
#define YGRegisterNatives(YGMakeCriticalNativeMethod) \
registerNatives( \
"com/facebook/yoga/YogaNode", \
{ \
YGMakeNativeMethod(jni_YGNodeNew), \
YGMakeNativeMethod(jni_YGNodeNewWithConfig), \
YGMakeCriticalNativeMethod(jni_YGNodeFree), \
YGMakeCriticalNativeMethod(jni_YGNodeReset), \
YGMakeCriticalNativeMethod(jni_YGNodeClearChildren), \
YGMakeCriticalNativeMethod(jni_YGNodeInsertChild), \
YGMakeCriticalNativeMethod(jni_YGNodeInsertSharedChild), \
YGMakeCriticalNativeMethod(jni_YGNodeRemoveChild), \
YGMakeNativeMethod(jni_YGNodeCalculateLayout), \
YGMakeCriticalNativeMethod(jni_YGNodeMarkDirty), \
YGMakeCriticalNativeMethod( \
jni_YGNodeMarkDirtyAndPropogateToDescendants), \
YGMakeCriticalNativeMethod(jni_YGNodeIsDirty), \
YGMakeCriticalNativeMethod(jni_YGNodeSetHasMeasureFunc), \
YGMakeCriticalNativeMethod(jni_YGNodeSetHasBaselineFunc), \
YGMakeCriticalNativeMethod(jni_YGNodeCopyStyle), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetDirection), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetDirection), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexDirection), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexDirection), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetJustifyContent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetJustifyContent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignItems), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignItems), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignSelf), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignSelf), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignContent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignContent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetPositionType), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPositionType), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexWrap), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetOverflow), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetOverflow), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetDisplay), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetDisplay), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlex), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexGrow), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexGrow), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexShrink), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexShrink), \
YGMakeNativeMethod(jni_YGNodeStyleGetFlexBasis), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasis), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasisPercent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasisAuto), \
YGMakeNativeMethod(jni_YGNodeStyleGetMargin), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMargin), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMarginPercent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMarginAuto), \
YGMakeNativeMethod(jni_YGNodeStyleGetPadding), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPadding), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPaddingPercent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetBorder), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetBorder), \
YGMakeNativeMethod(jni_YGNodeStyleGetPosition), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPosition), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPositionPercent), \
YGMakeNativeMethod(jni_YGNodeStyleGetWidth), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidth), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidthPercent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidthAuto), \
YGMakeNativeMethod(jni_YGNodeStyleGetHeight), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeight), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeightPercent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeightAuto), \
YGMakeNativeMethod(jni_YGNodeStyleGetMinWidth), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinWidth), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinWidthPercent), \
YGMakeNativeMethod(jni_YGNodeStyleGetMinHeight), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinHeight), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinHeightPercent), \
YGMakeNativeMethod(jni_YGNodeStyleGetMaxWidth), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxWidth), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxWidthPercent), \
YGMakeNativeMethod(jni_YGNodeStyleGetMaxHeight), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxHeight), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxHeightPercent), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAspectRatio), \
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAspectRatio), \
YGMakeCriticalNativeMethod(jni_YGNodeGetInstanceCount), \
YGMakeCriticalNativeMethod(jni_YGNodePrint), \
YGMakeNativeMethod(jni_YGNodeClone), \
YGMakeCriticalNativeMethod(jni_YGNodeSetOwner), \
}); \
registerNatives( \
"com/facebook/yoga/YogaConfig", \
{ \
YGMakeNativeMethod(jni_YGConfigNew), \
YGMakeNativeMethod(jni_YGConfigFree), \
YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled), \
YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults), \
YGMakeNativeMethod(jni_YGConfigSetPrintTreeFlag), \
YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor), \
YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour), \
YGMakeNativeMethod(jni_YGConfigSetLogger), \
YGMakeNativeMethod(jni_YGConfigSetHasCloneNodeFunc), \
YGMakeNativeMethod( \
jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour), \
});
void jni_bindNativeMethods(alias_ref<jclass>, jboolean useFastCall) {
if (useFastCall) {
YGRegisterNatives(YGRealMakeCriticalNativeMethod);
} else {
YGRegisterNatives(YGWrapCriticalNativeMethodForRegularCall);
}
}
#define YGMakeCriticalNativeMethod(name) makeCriticalNativeMethod(#name, name)
jint JNI_OnLoad(JavaVM* vm, void*) {
return initialize(vm, [] {
registerNatives(
"com/facebook/yoga/YogaJNI",
"com/facebook/yoga/YogaNode",
{
YGMakeNativeMethod(jni_bindNativeMethods),
YGMakeNativeMethod(jni_YGNodeNew),
YGMakeNativeMethod(jni_YGNodeNewWithConfig),
YGMakeCriticalNativeMethod(jni_YGNodeFree),
YGMakeCriticalNativeMethod(jni_YGNodeReset),
YGMakeCriticalNativeMethod(jni_YGNodeClearChildren),
YGMakeCriticalNativeMethod(jni_YGNodeInsertChild),
YGMakeCriticalNativeMethod(jni_YGNodeInsertSharedChild),
YGMakeCriticalNativeMethod(jni_YGNodeRemoveChild),
YGMakeCriticalNativeMethod(jni_YGNodeSetIsReferenceBaseline),
YGMakeCriticalNativeMethod(jni_YGNodeIsReferenceBaseline),
YGMakeNativeMethod(jni_YGNodeCalculateLayout),
YGMakeCriticalNativeMethod(jni_YGNodeMarkDirty),
YGMakeCriticalNativeMethod(
jni_YGNodeMarkDirtyAndPropogateToDescendants),
YGMakeCriticalNativeMethod(jni_YGNodeIsDirty),
YGMakeCriticalNativeMethod(jni_YGNodeSetHasMeasureFunc),
YGMakeCriticalNativeMethod(jni_YGNodeSetHasBaselineFunc),
YGMakeCriticalNativeMethod(jni_YGNodeCopyStyle),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetDirection),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetDirection),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexDirection),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexDirection),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetJustifyContent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetJustifyContent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignItems),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignItems),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignSelf),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignSelf),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAlignContent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAlignContent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetPositionType),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPositionType),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexWrap),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetOverflow),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetOverflow),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetDisplay),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetDisplay),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlex),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexGrow),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexGrow),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetFlexShrink),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexShrink),
YGMakeNativeMethod(jni_YGNodeStyleGetFlexBasis),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasis),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasisPercent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetFlexBasisAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetMargin),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMargin),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMarginPercent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMarginAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetPadding),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPadding),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPaddingPercent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetBorder),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetBorder),
YGMakeNativeMethod(jni_YGNodeStyleGetPosition),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPosition),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetPositionPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetWidth),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidth),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidthPercent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetWidthAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetHeight),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeight),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeightPercent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetHeightAuto),
YGMakeNativeMethod(jni_YGNodeStyleGetMinWidth),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinWidth),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinWidthPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetMinHeight),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinHeight),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMinHeightPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetMaxWidth),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxWidth),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxWidthPercent),
YGMakeNativeMethod(jni_YGNodeStyleGetMaxHeight),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxHeight),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetMaxHeightPercent),
YGMakeCriticalNativeMethod(jni_YGNodeStyleGetAspectRatio),
YGMakeCriticalNativeMethod(jni_YGNodeStyleSetAspectRatio),
YGMakeCriticalNativeMethod(jni_YGNodeGetInstanceCount),
YGMakeCriticalNativeMethod(jni_YGNodePrint),
YGMakeNativeMethod(jni_YGNodeClone),
YGMakeCriticalNativeMethod(jni_YGNodeSetOwner),
});
registerNatives(
"com/facebook/yoga/YogaConfig",
{
YGMakeNativeMethod(jni_YGConfigNew),
YGMakeNativeMethod(jni_YGConfigFree),
YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled),
YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults),
YGMakeNativeMethod(jni_YGConfigSetPrintTreeFlag),
YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor),
YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour),
YGMakeNativeMethod(jni_YGConfigSetLogger),
YGMakeNativeMethod(jni_YGConfigSetHasCloneNodeFunc),
YGMakeNativeMethod(
jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour),
});
});
}

Двоичные данные
ReactAndroid/src/main/jni/third-party/jsc/jni/arm64-v8a/libjsc.so поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
ReactAndroid/src/main/jni/third-party/jsc/jni/x86_64/libjsc.so поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
ReactAndroid/src/main/jniLibs/arm64-v8a/libicu_common.so Normal file

Двоичный файл не отображается.

Двоичные данные
ReactAndroid/src/main/jniLibs/x86_64/libicu_common.so Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -1,5 +1,5 @@
load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library", "rn_android_resource", "rn_prebuilt_jar")
load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library")
rn_android_library(
name = "support-v4",

Просмотреть файл

@ -1,4 +1,4 @@
load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "react_native_tests_target", "rn_robolectric_test")
load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "rn_robolectric_test")
rn_robolectric_test(
name = "layoutanimation",

Просмотреть файл

@ -67,13 +67,14 @@ public:
std::string name;
size_t callbacks;
bool isPromise;
std::function<void(folly::dynamic, Callback, Callback)> func;
std::function<folly::dynamic(folly::dynamic)> syncFunc;
const char *getType() {
assert(func || syncFunc);
return func ? (callbacks == 2 ? "promise" : "async") : "sync";
return func ? (isPromise ? "promise" : "async") : "sync";
}
// std::function/lambda ctors
@ -82,24 +83,36 @@ public:
std::function<void()>&& afunc)
: name(std::move(aname))
, callbacks(0)
, isPromise(false)
, func(std::bind(std::move(afunc))) {}
Method(std::string aname,
std::function<void(folly::dynamic)>&& afunc)
: name(std::move(aname))
, callbacks(0)
, func(std::bind(std::move(afunc), _1)) {}
, isPromise(false)
, func(std::bind(std::move(afunc), std::placeholders::_1)) {}
Method(std::string aname,
std::function<void(folly::dynamic, Callback)>&& afunc)
: name(std::move(aname))
, callbacks(1)
, func(std::bind(std::move(afunc), _1, _2)) {}
, isPromise(false)
, func(std::bind(std::move(afunc), std::placeholders::_1, std::placeholders::_2)) {}
Method(std::string aname,
std::function<void(folly::dynamic, Callback, Callback)>&& afunc)
: name(std::move(aname))
, callbacks(2)
, isPromise(true)
, func(std::move(afunc)) {}
Method(std::string aname,
std::function<void(folly::dynamic, Callback, Callback)>&& afunc,
AsyncTagType)
: name(std::move(aname))
, callbacks(2)
, isPromise(false)
, func(std::move(afunc)) {}
// method pointer ctors
@ -108,25 +121,39 @@ public:
Method(std::string aname, T* t, void (T::*method)())
: name(std::move(aname))
, callbacks(0)
, isPromise(false)
, func(std::bind(method, t)) {}
template <typename T>
Method(std::string aname, T* t, void (T::*method)(folly::dynamic))
: name(std::move(aname))
, callbacks(0)
, func(std::bind(method, t, _1)) {}
, isPromise(false)
, func(std::bind(method, t, std::placeholders::_1)) {}
template <typename T>
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback))
: name(std::move(aname))
, callbacks(1)
, func(std::bind(method, t, _1, _2)) {}
, isPromise(false)
, func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2)) {}
template <typename T>
Method(std::string aname, T* t, void (T::*method)(folly::dynamic, Callback, Callback))
: name(std::move(aname))
, callbacks(2)
, func(std::bind(method, t, _1, _2, _3)) {}
, isPromise(true)
, func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) {}
template <typename T>
Method(std::string aname,
T* t,
void (T::*method)(folly::dynamic, Callback, Callback),
AsyncTagType)
: name(std::move(aname))
, callbacks(2)
, isPromise(false)
, func(std::bind(method, t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) {}
// sync std::function/lambda ctors
@ -139,6 +166,7 @@ public:
SyncTagType)
: name(std::move(aname))
, callbacks(0)
, isPromise(false)
, syncFunc([afunc=std::move(afunc)] (const folly::dynamic&)
{ return afunc(); })
{}
@ -148,6 +176,7 @@ public:
SyncTagType)
: name(std::move(aname))
, callbacks(0)
, isPromise(false)
, syncFunc(std::move(afunc))
{}
};

Просмотреть файл

@ -136,6 +136,8 @@ void CxxNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params
if (callId != -1) {
fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", callId);
}
#else
(void)(callId);
#endif
SystraceSection s(method.name.c_str());
try {

Просмотреть файл

@ -18,7 +18,7 @@ namespace react {
static const char *errorPrefix = "Malformed calls from JS: ";
std::vector<MethodCall> parseMethodCalls(folly::dynamic&& jsonData) throw(std::invalid_argument) {
std::vector<MethodCall> parseMethodCalls(folly::dynamic&& jsonData) {
if (jsonData.isNull()) {
return {};
}
@ -77,4 +77,3 @@ std::vector<MethodCall> parseMethodCalls(folly::dynamic&& jsonData) throw(std::i
}
}}

Просмотреть файл

@ -27,6 +27,7 @@ struct MethodCall {
, callId(cid) {}
};
std::vector<MethodCall> parseMethodCalls(folly::dynamic&& calls) throw(std::invalid_argument);
/// \throws std::invalid_argument
std::vector<MethodCall> parseMethodCalls(folly::dynamic&& calls);
} }

Просмотреть файл

@ -90,13 +90,13 @@ folly::Optional<ModuleConfig> ModuleRegistry::getConfig(const std::string& name)
if (it == modulesByName_.end()) {
if (unknownModules_.find(name) != unknownModules_.end()) {
return nullptr;
return folly::none;
}
if (!moduleNotFoundCallback_ ||
!moduleNotFoundCallback_(name) ||
(it = modulesByName_.find(name)) == modulesByName_.end()) {
unknownModules_.insert(name);
return nullptr;
return folly::none;
}
}
size_t index = it->second;
@ -143,7 +143,7 @@ folly::Optional<ModuleConfig> ModuleRegistry::getConfig(const std::string& name)
if (config.size() == 2 && config[1].empty()) {
// no constants or methods
return nullptr;
return folly::none;
} else {
return ModuleConfig{index, config};
}

Просмотреть файл

@ -161,6 +161,8 @@ void NativeToJsBridge::callFunction(
"JSCall",
systraceCookie);
SystraceSection s("NativeToJsBridge::callFunction", "module", module, "method", method);
#else
(void)(systraceCookie);
#endif
// This is safe because we are running on the executor's thread: it won't
// destruct until after it's been unregistered (which we check above) and
@ -191,6 +193,8 @@ void NativeToJsBridge::invokeCallback(double callbackId, folly::dynamic&& argume
"<callback>",
systraceCookie);
SystraceSection s("NativeToJsBridge::invokeCallback");
#else
(void)(systraceCookie);
#endif
executor->invokeCallback(callbackId, arguments);
});

Просмотреть файл

@ -23,7 +23,7 @@ struct RecoverableError : public std::exception {
: m_what { "facebook::react::Recoverable: " + what_ }
{}
virtual const char* what() const throw() override { return m_what.c_str(); }
virtual const char* what() const noexcept override { return m_what.c_str(); }
/**
* runRethrowingAsRecoverable

Просмотреть файл

@ -114,6 +114,25 @@ auto SampleCxxModule::getMethods() -> std::vector<Method> {
sample_->hello();
return nullptr;
}, SyncTag),
Method("addIfPositiveAsPromise", [](dynamic args, Callback cb, Callback cbError) {
auto a = jsArgAsDouble(args, 0);
auto b = jsArgAsDouble(args, 1);
if (a < 0 || b < 0) {
cbError({"Negative number!"});
} else {
cb({a + b});
}
}),
Method("addIfPositiveAsAsync", [](dynamic args, Callback cb, Callback cbError) {
auto a = jsArgAsDouble(args, 0);
auto b = jsArgAsDouble(args, 1);
if (a < 0 || b < 0) {
cbError({"Negative number!"});
} else {
cb({a + b});
}
}, AsyncTag),
};
}

Просмотреть файл

@ -73,7 +73,7 @@ std::string AttributedString::getString() const {
}
bool AttributedString::operator==(const AttributedString &rhs) const {
return fragments_ != rhs.fragments_;
return fragments_ == rhs.fragments_;
}
bool AttributedString::operator!=(const AttributedString &rhs) const {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше