Merge branch 'master' into 0.58-stable
This commit is contained in:
Коммит
696bd89013
|
@ -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'));
|
||||
|
|
|
@ -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/arm64-v8a/libjsc.so
поставляемый
Normal file
Двоичный файл не отображается.
Двоичные данные
ReactAndroid/src/main/jni/third-party/jsc/jni/x86_64/libjsc.so
поставляемый
Normal file
Двоичные данные
ReactAndroid/src/main/jni/third-party/jsc/jni/x86_64/libjsc.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 {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче