Merge commit 'c8f571fdad9d632ab618d53520b4365d4e464423' into amgleitman/0.64-merge-head

This commit is contained in:
Adam Gleitman 2021-09-03 13:52:27 -07:00
Родитель 23693a47f2 c8f571fdad
Коммит 2dfcf658bf
58 изменённых файлов: 1277 добавлений и 179 удалений

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

@ -101,6 +101,7 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
this._component.getNativeScrollRef()['_internalInstanceHandle']
?.stateNode?.canonical != null) ||
(this._component.getScrollResponder != null &&
this._component.getScrollResponder() != null &&
this._component.getScrollResponder().getNativeScrollRef != null &&
this._component.getScrollResponder().getNativeScrollRef() != null &&
this._component.getScrollResponder().getNativeScrollRef()[
@ -112,26 +113,22 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
_waitForUpdate = (): void => {
// If this works well on iOS, we should remove this check
if (Platform.OS === 'android') {
if (this._isFabric()) {
if (this._animatedComponentId === -1) {
this._animatedComponentId = animatedComponentNextId++;
}
NativeAnimatedHelper.API.setWaitingForIdentifier(
this._animatedComponentId,
);
if (this._isFabric()) {
if (this._animatedComponentId === -1) {
this._animatedComponentId = animatedComponentNextId++;
}
NativeAnimatedHelper.API.setWaitingForIdentifier(
this._animatedComponentId,
);
}
};
_markUpdateComplete = (): void => {
// If this works well on iOS, we should remove this check
if (Platform.OS === 'android') {
if (this._isFabric()) {
NativeAnimatedHelper.API.unsetWaitingForIdentifier(
this._animatedComponentId,
);
}
if (this._isFabric()) {
NativeAnimatedHelper.API.unsetWaitingForIdentifier(
this._animatedComponentId,
);
}
};

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

@ -6,6 +6,7 @@
*
* @format
* @flow
* @generate-docs
*/
'use strict';
@ -29,10 +30,10 @@ type IndicatorSize = number | 'small' | 'large';
type IOSProps = $ReadOnly<{|
/**
* Whether the indicator should hide when not animating (true by default).
*
* See https://reactnative.dev/docs/activityindicator.html#hideswhenstopped
*/
Whether the indicator should hide when not animating.
@platform ios
*/
hidesWhenStopped?: ?boolean,
|}>;
type Props = $ReadOnly<{|
@ -40,33 +41,27 @@ type Props = $ReadOnly<{|
...IOSProps,
/**
* Whether to show the indicator (true, the default) or hide it (false).
*
* See https://reactnative.dev/docs/activityindicator.html#animating
Whether to show the indicator (`true`) or hide it (`false`).
*/
animating?: ?boolean,
/**
* The foreground color of the spinner (default is gray).
*
* See https://reactnative.dev/docs/activityindicator.html#color
*/
The foreground color of the spinner.
@default {@platform android} `null` (system accent default color)
@default {@platform ios} '#999999'
*/
color?: ?ColorValue,
/**
* Size of the indicator (default is 'small').
* Passing a number to the size prop is only supported on Android.
*
* See https://reactnative.dev/docs/activityindicator.html#size
*/
Size of the indicator.
@type enum(`'small'`, `'large'`)
@type {@platform android} number
*/
size?: ?IndicatorSize,
|}>;
/**
* Displays a circular loading indicator.
*
* See https://reactnative.dev/docs/activityindicator.html
*/
const ActivityIndicator = (props: Props, forwardedRef?: any) => {
const {onLayout, style, size, ...restProps} = props;
let sizeStyle;
@ -115,6 +110,68 @@ const ActivityIndicator = (props: Props, forwardedRef?: any) => {
);
};
/**
Displays a circular loading indicator.
```SnackPlayer name=ActivityIndicator%20Function%20Component%20Example
import React from "react";
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
const App = () => (
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator />
<ActivityIndicator size="large" />
<ActivityIndicator size="small" color="#0000ff" />
<ActivityIndicator size="large" color="#00ff00" />
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center"
},
horizontal: {
flexDirection: "row",
justifyContent: "space-around",
padding: 10
}
});
export default App;
```
```SnackPlayer name=ActivityIndicator%20Class%20Component%20Example
import React, { Component } from "react";
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
class App extends Component {
render() {
return (
<View style={[styles.container, styles.horizontal]}>
<ActivityIndicator />
<ActivityIndicator size="large" />
<ActivityIndicator size="small" color="#0000ff" />
<ActivityIndicator size="large" color="#00ff00" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center"
},
horizontal: {
flexDirection: "row",
justifyContent: "space-around",
padding: 10
}
});
export default App;
```
*/
const ActivityIndicatorWithRef: React.AbstractComponent<
Props,
HostComponent<mixed>,

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

@ -6,6 +6,7 @@
*
* @format
* @flow
* @generate-docs
*/
'use strict';
@ -31,67 +32,100 @@ import type {
type ButtonProps = $ReadOnly<{|
/**
* Text to display inside the button
Text to display inside the button. On Android the given title will be
converted to the uppercased form.
*/
title: string,
/**
* Handler to be called when the user taps the button
Handler to be called when the user taps the button. The first function
argument is an event in form of [PressEvent](pressevent).
*/
onPress: (event?: PressEvent) => mixed,
/**
* If true, doesn't play system sound on touch (Android Only)
**/
If `true`, doesn't play system sound on touch.
@platform android
@default false
*/
touchSoundDisabled?: ?boolean,
/**
* Color of the text (iOS), or background color of the button (Android)
Color of the text (iOS), or background color of the button (Android).
@default {@platform android} '#2196F3'
@default {@platform ios} '#007AFF'
*/
color?: ?ColorValue,
/**
* TV preferred focus (see documentation for the View component).
TV preferred focus.
@platform tv
@default false
*/
hasTVPreferredFocus?: ?boolean,
/**
* TV next focus down (see documentation for the View component).
*
* @platform android
Designates the next view to receive focus when the user navigates down. See
the [Android documentation][android:nextFocusDown].
[android:nextFocusDown]:
https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusDown
@platform android, tv
*/
nextFocusDown?: ?number,
/**
* TV next focus forward (see documentation for the View component).
*
* @platform android
Designates the next view to receive focus when the user navigates forward.
See the [Android documentation][android:nextFocusForward].
[android:nextFocusForward]:
https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusForward
@platform android, tv
*/
nextFocusForward?: ?number,
/**
* TV next focus left (see documentation for the View component).
*
* @platform android
Designates the next view to receive focus when the user navigates left. See
the [Android documentation][android:nextFocusLeft].
[android:nextFocusLeft]:
https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusLeft
@platform android, tv
*/
nextFocusLeft?: ?number,
/**
* TV next focus right (see documentation for the View component).
*
* @platform android
Designates the next view to receive focus when the user navigates right. See
the [Android documentation][android:nextFocusRight].
[android:nextFocusRight]:
https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusRight
@platform android, tv
*/
nextFocusRight?: ?number,
/**
* TV next focus up (see documentation for the View component).
*
* @platform android
Designates the next view to receive focus when the user navigates up. See
the [Android documentation][android:nextFocusUp].
[android:nextFocusUp]:
https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusUp
@platform android, tv
*/
nextFocusUp?: ?number,
/**
* Text to display for blindness accessibility features
Text to display for blindness accessibility features.
*/
accessibilityLabel?: ?string,
/**
@ -113,12 +147,14 @@ type ButtonProps = $ReadOnly<{|
onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed,
/**
* If true, disable all interactions for this component.
If `true`, disable all interactions for this component.
@default false
*/
disabled?: ?boolean,
/**
* Used to locate this view in end-to-end tests.
Used to locate this view in end-to-end tests.
*/
testID?: ?string,
@ -163,31 +199,114 @@ type ButtonProps = $ReadOnly<{|
|}>;
/**
* A basic button component that should render nicely on any platform. Supports
* a minimal level of customization.
*
* <center><img src="img/buttonExample.png"></img></center>
*
* If this button doesn't look right for your app, you can build your own
* button using [TouchableOpacity](docs/touchableopacity.html)
* or [TouchableNativeFeedback](docs/touchablenativefeedback.html).
* For inspiration, look at the [source code for this button component](https://github.com/facebook/react-native/blob/master/Libraries/Components/Button.js).
* Or, take a look at the [wide variety of button components built by the community](https://js.coach/react-native?search=button).
*
* Example usage:
*
* ```
* import { Button } from 'react-native';
* ...
*
* <Button
* onPress={onPressLearnMore}
* title="Learn More"
* color="#841584"
* accessibilityLabel="Learn more about this purple button"
* />
* ```
*
A basic button component that should render nicely on any platform. Supports a
minimal level of customization.
If this button doesn't look right for your app, you can build your own button
using [TouchableOpacity](touchableopacity) or
[TouchableWithoutFeedback](touchablewithoutfeedback). For inspiration, look at
the [source code for this button component][button:source]. Or, take a look at
the [wide variety of button components built by the community]
[button:examples].
[button:source]:
https://github.com/facebook/react-native/blob/master/Libraries/Components/Button.js
[button:examples]:
https://js.coach/?menu%5Bcollections%5D=React%20Native&page=1&query=button
```jsx
<Button
onPress={onPressLearnMore}
title="Learn More"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
```
```SnackPlayer name=Button%20Example
import React from 'react';
import { StyleSheet, Button, View, SafeAreaView, Text, Alert } from 'react-native';
const Separator = () => (
<View style={styles.separator} />
);
const App = () => (
<SafeAreaView style={styles.container}>
<View>
<Text style={styles.title}>
The title and onPress handler are required. It is recommended to set accessibilityLabel to help make your app usable by everyone.
</Text>
<Button
title="Press me"
onPress={() => Alert.alert('Simple Button pressed')}
/>
</View>
<Separator />
<View>
<Text style={styles.title}>
Adjust the color in a way that looks standard on each platform. On iOS, the color prop controls the color of the text. On Android, the color adjusts the background color of the button.
</Text>
<Button
title="Press me"
color="#f194ff"
onPress={() => Alert.alert('Button with adjusted color pressed')}
/>
</View>
<Separator />
<View>
<Text style={styles.title}>
All interaction for the component are disabled.
</Text>
<Button
title="Press me"
disabled
onPress={() => Alert.alert('Cannot press this one')}
/>
</View>
<Separator />
<View>
<Text style={styles.title}>
This layout strategy lets the title define the width of the button.
</Text>
<View style={styles.fixToText}>
<Button
title="Left button"
onPress={() => Alert.alert('Left button pressed')}
/>
<Button
title="Right button"
onPress={() => Alert.alert('Right button pressed')}
/>
</View>
</View>
</SafeAreaView>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
marginHorizontal: 16,
},
title: {
textAlign: 'center',
marginVertical: 8,
},
fixToText: {
flexDirection: 'row',
justifyContent: 'space-between',
},
separator: {
marginVertical: 8,
borderBottomColor: '#737373',
borderBottomWidth: StyleSheet.hairlineWidth,
},
});
export default App;
```
*/
class Button extends React.Component<ButtonProps> {

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

@ -36,26 +36,30 @@ export type Props = $ReadOnly<{|
...ViewProps,
/**
* Whether the switch is disabled. Defaults to false.
If true the user won't be able to toggle the switch.
@default false
*/
disabled?: ?boolean,
/**
* Boolean value of the switch. Defaults to false.
The value of the switch. If true the switch will be turned on.
@default false
*/
value?: ?boolean,
/**
* Custom color for the switch thumb.
Color of the foreground switch grip. If this is set on iOS, the switch grip will lose its drop shadow.
*/
thumbColor?: ?ColorValue,
/**
* Custom colors for the switch track.
*
* NOTE: On iOS when the switch value is false, the track shrinks into the
* border. If you want to change the color of the background exposed by the
* shrunken track, use `ios_backgroundColor`.
Custom colors for the switch track.
_iOS_: When the switch value is false, the track shrinks into the border. If you want to change the
color of the background exposed by the shrunken track, use
[`ios_backgroundColor`](https://reactnative.dev/docs/switch#ios_backgroundColor).
*/
trackColor?: ?$ReadOnly<{|
false?: ?ColorValue,
@ -63,36 +67,67 @@ export type Props = $ReadOnly<{|
|}>,
/**
* On iOS, custom color for the background. This background color can be seen
* either when the switch value is false or when the switch is disabled (and
* the switch is translucent).
On iOS, custom color for the background. This background color can be
seen either when the switch value is false or when the switch is
disabled (and the switch is translucent).
*/
ios_backgroundColor?: ?ColorValue,
/**
* Called when the user tries to change the value of the switch.
*
* Receives the change event as an argument. If you want to only receive the
* new value, use `onValueChange` instead.
Invoked when the user tries to change the value of the switch. Receives
the change event as an argument. If you want to only receive the new
value, use `onValueChange` instead.
*/
onChange?: ?(event: SwitchChangeEvent) => Promise<void> | void,
/**
* Called when the user tries to change the value of the switch.
*
* Receives the new value as an argument. If you want to instead receive an
* event, use `onChange`.
Invoked when the user tries to change the value of the switch. Receives
the new value as an argument. If you want to instead receive an event,
use `onChange`.
*/
onValueChange?: ?(value: boolean) => Promise<void> | void,
|}>;
/**
* A visual toggle between two mutually exclusive states.
*
* This is a controlled component that requires an `onValueChange` callback that
* updates the `value` prop in order for the component to reflect user actions.
* If the `value` prop is not updated, the component will continue to render the
* supplied `value` prop instead of the expected result of any user actions.
Renders a boolean input.
This is a controlled component that requires an `onValueChange`
callback that updates the `value` prop in order for the component to
reflect user actions. If the `value` prop is not updated, the
component will continue to render the supplied `value` prop instead of
the expected result of any user actions.
```SnackPlayer name=Switch
import React, { useState } from "react";
import { View, Switch, StyleSheet } from "react-native";
const App = () => {
const [isEnabled, setIsEnabled] = useState(false);
const toggleSwitch = () => setIsEnabled(previousState => !previousState);
return (
<View style={styles.container}>
<Switch
trackColor={{ false: "#767577", true: "#81b0ff" }}
thumbColor={isEnabled ? "#f5dd4b" : "#f4f3f4"}
ios_backgroundColor="#3e3e3e"
onValueChange={toggleSwitch}
value={isEnabled}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
}
});
export default App;
```
*/
class Switch extends React.Component<Props> {
_nativeSwitchRef: ?React.ElementRef<

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

@ -16,7 +16,7 @@ import invariant from 'invariant';
const turboModuleProxy = global.__turboModuleProxy;
export function get<T: TurboModule>(name: string): ?T {
function requireModule<T: TurboModule>(name: string, schema?: ?$FlowFixMe): ?T {
// Bridgeless mode requires TurboModules
if (!global.RN$Bridgeless) {
// Backward compatibility layer during migration.
@ -27,15 +27,40 @@ export function get<T: TurboModule>(name: string): ?T {
}
if (turboModuleProxy != null) {
const module: ?T = turboModuleProxy(name);
const module: ?T =
schema != null ? turboModuleProxy(name, schema) : turboModuleProxy(name);
return module;
}
return null;
}
export function get<T: TurboModule>(name: string): ?T {
/**
* What is Schema?
*
* @react-native/babel-plugin-codegen will parse the NativeModule
* spec, and pass in the generated schema as the second argument
* to this function. The schem will then be used to perform method
* dispatch on, and translate arguments/return to and from the Native
* TurboModule object.
*/
const schema = arguments.length === 2 ? arguments[1] : undefined;
return requireModule<T>(name, schema);
}
export function getEnforcing<T: TurboModule>(name: string): T {
const module = get(name);
/**
* What is Schema?
*
* @react-native/babel-plugin-codegen will parse the NativeModule
* spec, and pass in the generated schema as the second argument
* to this function. The schem will then be used to perform method
* dispatch on, and translate arguments/return to and from the Native
* TurboModule object.
*/
const schema = arguments.length === 2 ? arguments[1] : undefined;
const module = requireModule<T>(name, schema);
invariant(
module != null,
`TurboModuleRegistry.getEnforcing(...): '${name}' could not be found. ` +

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

@ -510,8 +510,8 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0
FBLazyVector: 876a1bb2875a1daa12bbde86b69d1a6d5678270d
FBReactNativeSpec: 9aa555f235721bfc394fd78159c86402abf780f3
FBLazyVector: 112e81d0f6a88bd3f1e8e099254c65ec796a0448
FBReactNativeSpec: 511c832d0652b70c5546edf565182d6e0d74ceef
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
@ -522,33 +522,33 @@ SPEC CHECKSUMS:
glog: 789873d01e4b200777d0a09bc23d548446758699
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7
RCTRequired: 7233538814df062b6920352a6d565e986068605b
RCTTypeSafety: 8b30a16646bb6c4f6a2c9fb6edd52a1cd255005c
React: 0ae278f1d7b40f1373dd75972291dd4a90523db2
React-callinvoker: 4df7d54bc003e47dfd07d2d327c3fb76f9f6cfec
React-Core: e0e36cf70bc525f828218823fa7d1e5a8504ba6b
React-CoreModules: fb477147fbb8a8c826fa5fc75642d3df1e745e01
React-cxxreact: dfa59985848c3a21a1b02dc6fff6be6b8fad5205
React-jsi: c22c37acefd6344cef9d742d7343a16de77ea19e
React-jsiexecutor: 9cd81e2096083261fca77e5c967036507e7e3933
React-jsinspector: 05af2a2fabd2f7c5bf8828af2a934ee8a717d707
React-perflogger: 69c9e4bac7d144b075ffd269ebbb4bb381597143
React-RCTActionSheet: de020f8b53b66cb202e0d0bdc2679211d1c9cc20
React-RCTAnimation: 10858da1c2c0da129c72e613201418eb1e80ecf6
React-RCTBlob: ca0834d29ea1e6034a758a741f2b7c6c3439c229
React-RCTImage: 1e2ec22b4f31945a8a62fcd5a02633118b019306
React-RCTLinking: 5c27202eeebd2f093fb5504bd68032bbbb49bf66
React-RCTNetwork: fba49d8aa8948e5ecc2df444ed163227c3a8e517
React-RCTPushNotification: 40892bd25ee1c79ed4ae67af74f4d70561296e5b
React-RCTSettings: 95798dd8f98163daef355f3917be4391a1067358
React-RCTTest: 48da96285327312d2d689f73f0c2e0fe459f534c
React-RCTText: 001005052a86682a9f4df9df2887ce8a0f183eaf
React-RCTVibration: 7b07b0bcea9a33c797751f082ff7dd4f7c46066d
React-runtimeexecutor: e0423edf5cf04180d6ac79e7f1babdfb63189ca7
RCTRequired: 35b0c3ee46eedb3092f87ac4c3ea0e67bae1ca29
RCTTypeSafety: cf6cadae225f66eaa5af268cd6ab3fb9379bf297
React: 799643578fad09ba651073199630a48cd1635366
React-callinvoker: 9103637dc97d924edc3a76ff21e0e74d627b2e6f
React-Core: 3f230d8f22f59d07bd884c6e9726e535ce407b35
React-CoreModules: 782a9e7e2695b8dfe318db513ab9ce5e0c2a82f5
React-cxxreact: ea9f3b803d1582429dfcada83809face20c7b8a5
React-jsi: 5b2aacc2879d8e2dbc8beea004be8d5e28dc1d85
React-jsiexecutor: f5d575e4f9f6291f7d54caaefc5b7346cd70e9a0
React-jsinspector: 713ed70776df5cbc042f682629ec0ff65dec0641
React-perflogger: d800dc4faf31e5dda5d619e3327210bc224b4d14
React-RCTActionSheet: 11dd54c56e7511b949da070630ae3162a643dd4d
React-RCTAnimation: b27c4086bf859d0ecea0c9ea10b7949b43a3ad8c
React-RCTBlob: 7f2031a6c0439e3c638a54f998f4ca792829a694
React-RCTImage: 1592dbf3e8980c5c6e70512b017c5f3ff6a61175
React-RCTLinking: bb9bf15e12a0aaf25c304f73c7c1a072a35b5f2f
React-RCTNetwork: 214490b06eafcad8968e70d338e5420cee54855f
React-RCTPushNotification: 4520a6730e3b577623b6683c140ab859b777efd3
React-RCTSettings: 1d0df7dbc87d13b099538159f0fc5f72d3ab7d71
React-RCTTest: ef91f414ae03d43ffb25817eeda61fea324d04af
React-RCTText: f0391918f0e19a6020a9a359cc841596675ee7e2
React-RCTVibration: 293a921bbc1fef79b76f1fd4a734b17c3602073b
React-runtimeexecutor: dcf79bb0721d2f1fbc197cfbaa67ca28fc2fd6db
React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817
React-TurboModuleCxx-WinRTPort: 4e448bcb580726297008d210112015c1bb3099ee
ReactCommon: ec01c4d2bd15d6d6bbfe0c2bb4d314c0e26c4d66
Yoga: 6ccbafe84a40639080d19b5fd1b3d6733e51b99c
React-TurboModuleCxx-WinRTPort: a5a7492ad1f33eca57ba0403f4452c8138b136d7
ReactCommon: 0b3a9ad4019381e84deb6833ad327d3f09823b08
Yoga: 6e796a166e9199a448895cdd60ac3d3216d85736
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: d3ddf54cbfd92c34f45d8fb0c9166fe4730df5c0

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

@ -7,6 +7,7 @@
plugins {
id("com.android.application")
id("com.facebook.react.codegen")
}
/**

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

@ -16,7 +16,7 @@
#import <React/RCTTextDecorationLineType.h>
#import <React/RCTFontSmoothing.h> // TODO(OSS Candidate ISS#2710739)
#import <yoga/Yoga.h>
#if TARGET_OS_IPHONE && WEBKIT_IOS_10_APIS_AVAILABLE
#if TARGET_OS_IPHONE
#import <WebKit/WebKit.h>
#endif
@ -75,7 +75,7 @@ typedef NSURL RCTFileURL;
+ (UIDataDetectorTypes)UIDataDetectorTypes:(id)json;
#endif
#if TARGET_OS_IPHONE && WEBKIT_IOS_10_APIS_AVAILABLE
#if TARGET_OS_IPHONE
+ (WKDataDetectorTypes)WKDataDetectorTypes:(id)json;
#endif

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

@ -448,7 +448,6 @@ RCT_MULTI_ENUM_CONVERTER(
UIDataDetectorTypePhoneNumber,
unsignedLongLongValue)
#if WEBKIT_IOS_10_APIS_AVAILABLE
RCT_MULTI_ENUM_CONVERTER(
WKDataDetectorTypes,
(@{
@ -464,7 +463,6 @@ RCT_MULTI_ENUM_CONVERTER(
}),
WKDataDetectorTypePhoneNumber,
unsignedLongLongValue)
#endif // WEBKIT_IOS_10_APIS_AVAILABLE
#endif // !TARGET_OS_TV

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

@ -143,8 +143,3 @@
@throw _RCTNotImplementedException(_cmd, [self class]); \
} \
_Pragma("clang diagnostic pop")
/**
* Check if WebKit iOS 10.0 APIs are available.
*/
#define WEBKIT_IOS_10_APIS_AVAILABLE __has_include(<WebKit/WKAudiovisualMediaTypes.h>)

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

@ -36,6 +36,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) CGFloat snapToInterval;
@property (nonatomic, copy) NSString *snapToAlignment;
@property (nonatomic, assign) BOOL disableIntervalMomentum;
@property (nonatomic, assign) BOOL snapToStart;
@property (nonatomic, assign) BOOL snapToEnd;
@property (nonatomic, copy) NSArray<NSNumber *> *snapToOffsets;
@end

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

@ -106,7 +106,84 @@
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset
{
if (self.snapToInterval) {
if (self.snapToOffsets && self.snapToOffsets.count > 0) {
// An alternative to enablePaging and snapToInterval which allows setting custom
// stopping points that don't have to be the same distance apart. Often seen in
// apps which feature horizonally scrolling items. snapToInterval does not enforce
// scrolling one interval at a time but guarantees that the scroll will stop at
// a snap offset point.
// Find which axis to snap
BOOL isHorizontal = [self isHorizontal:scrollView];
CGFloat velocityAlongAxis = isHorizontal ? velocity.x : velocity.y;
CGFloat offsetAlongAxis = isHorizontal ? scrollView.contentOffset.x : scrollView.contentOffset.y;
// Calculate maximum content offset
CGSize viewportSize = self.bounds.size;
CGFloat maximumOffset = isHorizontal ? MAX(0, scrollView.contentSize.width - viewportSize.width)
: MAX(0, scrollView.contentSize.height - viewportSize.height);
// Calculate the snap offsets adjacent to the initial offset target
CGFloat targetOffset = isHorizontal ? targetContentOffset->x : targetContentOffset->y;
CGFloat smallerOffset = 0.0;
CGFloat largerOffset = maximumOffset;
for (unsigned long i = 0; i < self.snapToOffsets.count; i++) {
CGFloat offset = [[self.snapToOffsets objectAtIndex:i] floatValue];
if (offset <= targetOffset) {
if (targetOffset - offset < targetOffset - smallerOffset) {
smallerOffset = offset;
}
}
if (offset >= targetOffset) {
if (offset - targetOffset < largerOffset - targetOffset) {
largerOffset = offset;
}
}
}
// Calculate the nearest offset
CGFloat nearestOffset = targetOffset - smallerOffset < largerOffset - targetOffset ? smallerOffset : largerOffset;
CGFloat firstOffset = [[self.snapToOffsets firstObject] floatValue];
CGFloat lastOffset = [[self.snapToOffsets lastObject] floatValue];
// if scrolling after the last snap offset and snapping to the
// end of the list is disabled, then we allow free scrolling
if (!self.snapToEnd && targetOffset >= lastOffset) {
if (offsetAlongAxis >= lastOffset) {
// free scrolling
} else {
// snap to end
targetOffset = lastOffset;
}
} else if (!self.snapToStart && targetOffset <= firstOffset) {
if (offsetAlongAxis <= firstOffset) {
// free scrolling
} else {
// snap to beginning
targetOffset = firstOffset;
}
} else if (velocityAlongAxis > 0.0) {
targetOffset = largerOffset;
} else if (velocityAlongAxis < 0.0) {
targetOffset = smallerOffset;
} else {
targetOffset = nearestOffset;
}
// Make sure the new offset isn't out of bounds
targetOffset = MIN(MAX(0, targetOffset), maximumOffset);
// Set new targetContentOffset
if (isHorizontal) {
targetContentOffset->x = targetOffset;
} else {
targetContentOffset->y = targetOffset;
}
} else if (self.snapToInterval) {
// An alternative to enablePaging which allows setting custom stopping intervals,
// smaller than a full page size. Often seen in apps which feature horizonally
// scrolling items. snapToInterval does not enforce scrolling one interval at a time

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

@ -187,13 +187,24 @@ void RCTSetEnableOnDemandViewMounting(BOOL value)
_scrollView.contentInset = RCTUIEdgeInsetsFromEdgeInsets(newScrollViewProps.contentInset);
}
RCTEnhancedScrollView *scrollView = (RCTEnhancedScrollView *)_scrollView;
if (oldScrollViewProps.contentOffset != newScrollViewProps.contentOffset) {
_scrollView.contentOffset = RCTCGPointFromPoint(newScrollViewProps.contentOffset);
}
if (oldScrollViewProps.snapToAlignment != newScrollViewProps.snapToAlignment) {
((RCTEnhancedScrollView *)_scrollView).snapToAlignment =
RCTNSStringFromString(toString(newScrollViewProps.snapToAlignment));
scrollView.snapToAlignment = RCTNSStringFromString(toString(newScrollViewProps.snapToAlignment));
}
scrollView.snapToStart = newScrollViewProps.snapToStart;
scrollView.snapToEnd = newScrollViewProps.snapToEnd;
if (oldScrollViewProps.snapToOffsets != newScrollViewProps.snapToOffsets) {
NSMutableArray<NSNumber *> *snapToOffsets = [NSMutableArray array];
for (auto const &snapToOffset : newScrollViewProps.snapToOffsets) {
[snapToOffsets addObject:[NSNumber numberWithFloat:snapToOffset]];
}
scrollView.snapToOffsets = snapToOffsets;
}
MAP_SCROLL_VIEW_PROP(disableIntervalMomentum);

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

@ -122,6 +122,11 @@ static BackgroundExecutor RCTGetBackgroundExecutor()
_observers = [NSMutableArray array];
_scheduler = [self _createScheduler];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_handleContentSizeCategoryDidChangeNotification:)
name:UIContentSizeCategoryDidChangeNotification
object:nil];
}
return self;
@ -427,6 +432,23 @@ static BackgroundExecutor RCTGetBackgroundExecutor()
}];
}
- (void)_handleContentSizeCategoryDidChangeNotification:(NSNotification *)notification
{
RCTScheduler *scheduler = [self _scheduler];
[_surfaceRegistry enumerateWithBlock:^(NSEnumerator<RCTFabricSurface *> *enumerator) {
for (RCTFabricSurface *surface in enumerator) {
LayoutContext layoutContext = RCTGetLayoutContext();
LayoutConstraints layoutConstraints = RCTGetLayoutConstraintsForSize(surface.minimumSize, surface.maximumSize);
[scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints
layoutContext:layoutContext
surfaceId:surface.rootTag];
}
}];
}
#pragma mark - RCTSchedulerDelegate
- (void)schedulerDidFinishTransaction:(MountingCoordinator::Shared const &)mountingCoordinator

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

@ -18,6 +18,7 @@
#import <React/RCTSurfacePresenterStub.h>
#import <ReactCommon/RuntimeExecutor.h>
#import <react/utils/CalledOnceMovableOnlyFunction.h>
#import <react/utils/ContextContainer.h>
#import <react/utils/ManagedObjectWrapper.h>
@ -43,19 +44,43 @@ static ContextContainer::Shared RCTContextContainerFromBridge(RCTBridge *bridge)
static RuntimeExecutor RCTRuntimeExecutorFromBridge(RCTBridge *bridge)
{
RCTAssert(bridge, @"RCTRuntimeExecutorFromBridge: Bridge must not be nil.");
auto bridgeWeakWrapper = wrapManagedObjectWeakly([bridge batchedBridge] ?: bridge);
RuntimeExecutor runtimeExecutor = [bridgeWeakWrapper](
std::function<void(facebook::jsi::Runtime & runtime)> &&callback) {
[unwrapManagedObjectWeakly(bridgeWeakWrapper) invokeAsync:[bridgeWeakWrapper, callback = std::move(callback)]() {
std::function<void(facebook::jsi::Runtime &)> &&callbackArgument) {
#ifndef NDEBUG
// Here we wrap callback into a callable that will assert if the `callback` is not called before deallocation
// or called more than once.
// It's useful to see at which exact point in time those assumptions were violated.
auto sharedCallback = std::make_shared<CalledOnceMovableOnlyFunction<void, facebook::jsi::Runtime &>>(
[callback = std::move(callbackArgument)](facebook::jsi::Runtime &runtime) { callback(runtime); });
auto callback = std::function<void(facebook::jsi::Runtime &)>(
[sharedCallback](facebook::jsi::Runtime &runtime) { (*sharedCallback)(runtime); });
#else
auto callback = std::move(callbackArgument);
#endif
RCTBridge *bridge = unwrapManagedObjectWeakly(bridgeWeakWrapper);
RCTAssert(bridge, @"RCTRuntimeExecutorFromBridge: Bridge must not be nil at the moment of scheduling a call.");
[bridge invokeAsync:[bridgeWeakWrapper, callback = std::move(callback)]() {
RCTCxxBridge *batchedBridge = (RCTCxxBridge *)unwrapManagedObjectWeakly(bridgeWeakWrapper);
RCTAssert(batchedBridge, @"RCTRuntimeExecutorFromBridge: Bridge must not be nil at the moment of invocation.");
if (!batchedBridge) {
return;
}
auto runtime = (facebook::jsi::Runtime *)(batchedBridge.runtime);
RCTAssert(
runtime, @"RCTRuntimeExecutorFromBridge: Bridge must have a valid jsi::Runtime at the moment of invocation.");
if (!runtime) {
return;
}

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

@ -14,6 +14,11 @@ NS_ASSUME_NONNULL_BEGIN
- (void)attachToView:(UIView *)view;
- (void)detachFromView:(UIView *)view;
/*
* Offset of the attached view relative to the root component in points.
*/
@property (nonatomic, assign) CGPoint viewOriginOffset;
@end
NS_ASSUME_NONNULL_END

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

@ -78,11 +78,16 @@ struct ActiveTouch {
};
};
static void UpdateActiveTouchWithUITouch(ActiveTouch &activeTouch, UITouch *uiTouch, UIView *rootComponentView)
static void UpdateActiveTouchWithUITouch(
ActiveTouch &activeTouch,
UITouch *uiTouch,
UIView *rootComponentView,
CGPoint rootViewOriginOffset)
{
CGPoint offsetPoint = [uiTouch locationInView:activeTouch.componentView];
CGPoint screenPoint = [uiTouch locationInView:uiTouch.window];
CGPoint pagePoint = [uiTouch locationInView:rootComponentView];
pagePoint = CGPointMake(pagePoint.x + rootViewOriginOffset.x, pagePoint.y + rootViewOriginOffset.y);
activeTouch.touch.offsetPoint = RCTPointFromCGPoint(offsetPoint);
activeTouch.touch.screenPoint = RCTPointFromCGPoint(screenPoint);
@ -95,7 +100,7 @@ static void UpdateActiveTouchWithUITouch(ActiveTouch &activeTouch, UITouch *uiTo
}
}
static ActiveTouch CreateTouchWithUITouch(UITouch *uiTouch, UIView *rootComponentView)
static ActiveTouch CreateTouchWithUITouch(UITouch *uiTouch, UIView *rootComponentView, CGPoint rootViewOriginOffset)
{
UIView *componentView = uiTouch.view;
@ -109,7 +114,7 @@ static ActiveTouch CreateTouchWithUITouch(UITouch *uiTouch, UIView *rootComponen
activeTouch.componentView = componentView;
UpdateActiveTouchWithUITouch(activeTouch, uiTouch, rootComponentView);
UpdateActiveTouchWithUITouch(activeTouch, uiTouch, rootComponentView, rootViewOriginOffset);
return activeTouch;
}
@ -197,7 +202,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
- (void)_registerTouches:(NSSet<UITouch *> *)touches
{
for (UITouch *touch in touches) {
auto activeTouch = CreateTouchWithUITouch(touch, _rootComponentView);
auto activeTouch = CreateTouchWithUITouch(touch, _rootComponentView, _viewOriginOffset);
activeTouch.touch.identifier = _identifierPool.dequeue();
_activeTouches.emplace(touch, activeTouch);
}
@ -212,7 +217,7 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithTarget : (id)target action : (SEL)act
continue;
}
UpdateActiveTouchWithUITouch(iterator->second, touch, _rootComponentView);
UpdateActiveTouchWithUITouch(iterator->second, touch, _rootComponentView, _viewOriginOffset);
}
}

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

@ -9,6 +9,7 @@ plugins {
id("com.android.library")
id("maven")
id("de.undercouch.download")
id("com.facebook.react.codegen")
}
import java.nio.file.Paths

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

@ -719,6 +719,9 @@ import java.util.Queue;
+ updatedNodesCount);
if (mEventListenerInitializedForFabric && cyclesDetected == 0) {
ReactSoftException.logSoftException(TAG, new ReactNoCrashSoftException(ex));
} else if (mEventListenerInitializedForFabric) {
// Crashes in Debug, but not in Production
ReactSoftException.logSoftException(TAG, ex);
} else {
throw ex;
}

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

@ -68,4 +68,7 @@ public class ReactFeatureFlags {
/** Feature flag to use stopSurface when ReactRootView is unmounted. */
public static boolean enableStopSurfaceOnRootViewUnmount = false;
/** Use experimental SetState retry mechanism in view? */
public static boolean enableExperimentalStateUpdateRetry = false;
}

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

@ -28,7 +28,7 @@ rn_xplat_cxx_library(
visibility = ["PUBLIC"],
deps = [
react_native_xplat_target("better:better"),
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/animations:animations"),
react_native_xplat_target("react/renderer/uimanager:uimanager"),
react_native_xplat_target("react/renderer/scheduler:scheduler"),

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

@ -156,7 +156,19 @@ public class MountingManager {
logViewHierarchy(parentView);
}
getViewGroupManager(parentViewState).addView(parentView, view, index);
try {
getViewGroupManager(parentViewState).addView(parentView, view, index);
} catch (IllegalStateException e) {
// Wrap error with more context for debugging
throw new IllegalStateException(
"addViewAt: failed to insert view ["
+ tag
+ "] into parent ["
+ parentTag
+ "] at index "
+ index,
e);
}
// Display children after inserting
if (SHOW_CHANGED_VIEW_HIERARCHIES) {

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

@ -0,0 +1,73 @@
/*
* 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.react.uimanager;
import android.view.ViewGroup;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.config.ReactFeatureFlags;
/** This is a helper base class for ViewGroups that use Fabric State. */
public abstract class FabricStateBaseViewGroup extends ViewGroup {
public interface StateUpdateCallback {
WritableMap getStateUpdate();
}
private StateWrapper mStateWrapper = null;
public FabricStateBaseViewGroup(ThemedReactContext context) {
super(context);
}
public void setStateWrapper(StateWrapper stateWrapper) {
mStateWrapper = stateWrapper;
}
private static void setState(
final FabricStateBaseViewGroup view,
final StateWrapper stateWrapper,
final StateUpdateCallback stateUpdateCallback,
final int numTries) {
// The StateWrapper will change, breaking this loop, whenever the UpdateState MountItem
// is executed.
// The caller is responsible for detecting if data is up-to-date, and doing nothing, or
// detecting if state is stale and calling setState again.
if (stateWrapper != view.mStateWrapper) {
return;
}
// We arbitrarily bail out after a certain number of retries.
// This is a pretty large number: in practice I've seen this number go over 50
// with minimal/no visual jank.
if (numTries > 5 * 60) {
return;
}
stateWrapper.updateState(stateUpdateCallback.getStateUpdate());
// An `updateState` call can fail, and there's no way to verify if it succeeds besides
// waiting for a corresponding `StateUpdate` MountItem to be executed on some future UI tick.
// So.... to resolve conflicts with updateState, we just keep firing it until it succeeds or
// the View goes away.
if (ReactFeatureFlags.enableExperimentalStateUpdateRetry) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
setState(view, stateWrapper, stateUpdateCallback, numTries + 1);
}
});
}
}
public static void setState(
final FabricStateBaseViewGroup view,
final StateWrapper stateWrapper,
final StateUpdateCallback stateUpdateCallback) {
setState(view, stateWrapper, stateUpdateCallback, 0);
}
}

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

@ -1967,9 +1967,9 @@ electron-to-chromium@^1.3.322:
integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==
elliptic@^6.0.0:
version "6.5.2"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762"
integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==
version "6.5.3"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
dependencies:
bn.js "^4.4.0"
brorand "^1.0.1"

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

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

@ -0,0 +1,25 @@
# 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := reactconfig
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../
LOCAL_CFLAGS := \
-DLOG_TAG=\"Fabric\"
LOCAL_CFLAGS += -fexceptions -frtti -std=c++14 -Wall
LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES :=
include $(BUILD_SHARED_LIBRARY)

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

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

@ -58,7 +58,7 @@ rn_xplat_cxx_library(
"//xplat/folly:molly",
"//xplat/jsi:JSIDynamic",
"//xplat/jsi:jsi",
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/componentregistry:componentregistry"),
react_native_xplat_target("react/renderer/components/view:view"),
react_native_xplat_target("react/renderer/core:core"),
@ -85,7 +85,7 @@ fb_xplat_cxx_test(
":animations",
"//xplat/folly:molly",
"//xplat/third-party/gmock:gtest",
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/components/activityindicator:activityindicator"),
react_native_xplat_target("react/renderer/components/image:image"),
react_native_xplat_target("react/renderer/components/root:root"),

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

@ -150,7 +150,16 @@ ScrollViewProps::ScrollViewProps(
rawProps,
"disableIntervalMomentum",
sourceProps.disableIntervalMomentum,
{})) {}
{})),
snapToOffsets(convertRawProp(
rawProps,
"snapToOffsets",
sourceProps.snapToOffsets,
{})),
snapToStart(
convertRawProp(rawProps, "snapToStart", sourceProps.snapToStart, {})),
snapToEnd(
convertRawProp(rawProps, "snapToEnd", sourceProps.snapToEnd, {})) {}
#pragma mark - DebugStringConvertible
@ -261,7 +270,11 @@ SharedDebugStringConvertibleList ScrollViewProps::getDebugProps() const {
debugStringConvertibleItem(
"disableIntervalMomentum",
disableIntervalMomentum,
defaultScrollViewProps.disableIntervalMomentum)};
defaultScrollViewProps.disableIntervalMomentum),
debugStringConvertibleItem(
"snapToStart", snapToStart, defaultScrollViewProps.snapToStart),
debugStringConvertibleItem(
"snapToEnd", snapToEnd, defaultScrollViewProps.snapToEnd)};
}
#endif

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

@ -48,6 +48,9 @@ class ScrollViewProps final : public ViewProps {
Float snapToInterval{};
ScrollViewSnapToAlignment snapToAlignment{};
bool disableIntervalMomentum{false};
std::vector<Float> snapToOffsets{};
bool snapToStart{true};
bool snapToEnd{true};
#pragma mark - DebugStringConvertible

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

@ -45,7 +45,7 @@ void ViewShadowNode::initialize() noexcept {
viewProps.opacity != 1.0 || viewProps.transform != Transform{} ||
viewProps.elevation != 0 ||
(viewProps.zIndex.has_value() &&
viewProps.yogaStyle.positionType() != YGPositionTypeAbsolute) ||
viewProps.yogaStyle.positionType() == YGPositionTypeAbsolute) ||
viewProps.yogaStyle.display() == YGDisplayNone ||
viewProps.getClipsContentToBounds() ||
isColorMeaningful(viewProps.shadowColor) ||

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

@ -59,7 +59,7 @@ rn_xplat_cxx_library(
react_native_xplat_target("react/renderer/mounting:mounting"),
react_native_xplat_target("react/renderer/uimanager:uimanager"),
react_native_xplat_target("react/renderer/templateprocessor:templateprocessor"),
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/componentregistry:componentregistry"),
react_native_xplat_target("react/renderer/debug:debug"),
react_native_xplat_target("react/renderer/components/root:root"),

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

@ -61,7 +61,7 @@ rn_xplat_cxx_library(
react_native_xplat_target("react/renderer/uimanager:uimanager"),
react_native_xplat_target("react/renderer/componentregistry:componentregistry"),
react_native_xplat_target("react/renderer/debug:debug"),
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("utils:utils"),
],
)
@ -82,7 +82,7 @@ fb_xplat_cxx_test(
":templateprocessor",
"//xplat/folly:molly",
"//xplat/third-party/gmock:gtest",
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/components/activityindicator:activityindicator"),
react_native_xplat_target("react/renderer/components/image:image"),
react_native_xplat_target("react/renderer/components/root:root"),

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

@ -57,7 +57,7 @@ rn_xplat_cxx_library(
"//xplat/folly:molly",
"//xplat/jsi:JSIDynamic",
"//xplat/jsi:jsi",
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/components/view:view"),
react_native_xplat_target("react/renderer/mounting:mounting"),
react_native_xplat_target("react/renderer/core:core"),
@ -83,7 +83,7 @@ fb_xplat_cxx_test(
":uimanager",
"//xplat/folly:molly",
"//xplat/third-party/gmock:gtest",
react_native_xplat_target("config:config"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/components/activityindicator:activityindicator"),
react_native_xplat_target("react/renderer/components/image:image"),
react_native_xplat_target("react/renderer/components/root:root"),

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

@ -54,8 +54,8 @@ std::shared_ptr<UIManagerBinding> UIManagerBinding::createAndInstallIfNeeded(
}
UIManagerBinding::~UIManagerBinding() {
LOG(WARNING) << "UIManager::~UIManager() was called (address: " << this
<< ").";
LOG(WARNING) << "UIManagerBinding::~UIManagerBinding() was called (address: "
<< this << ").";
// We must detach the `UIBinding` on deallocation to prevent accessing
// deallocated `UIManagerBinding`.

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

@ -0,0 +1,87 @@
/*
* 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.
*/
#include <functional>
namespace facebook {
namespace react {
/*
* Implements a moveable-only function that asserts if called more than once
* or destroyed before calling.
* Useful for use in debug mode to ensure such guarantees.
*/
template <typename ReturnT = void, typename... ArgumentT>
class CalledOnceMovableOnlyFunction {
using T = ReturnT(ArgumentT...);
std::function<T> function_;
bool wasCalled_;
bool wasMovedFrom_;
public:
CalledOnceMovableOnlyFunction(std::function<T> &&function)
: function_(std::move(function)) {
wasCalled_ = false;
wasMovedFrom_ = false;
}
~CalledOnceMovableOnlyFunction() {
assert(
(wasCalled_ || wasMovedFrom_) &&
"`CalledOnceMovableOnlyFunction` is destroyed before being called.");
}
/*
* Not copyable.
*/
CalledOnceMovableOnlyFunction(CalledOnceMovableOnlyFunction const &other) =
delete;
CalledOnceMovableOnlyFunction &operator=(
CalledOnceMovableOnlyFunction const &other) = delete;
/*
* Movable.
*/
CalledOnceMovableOnlyFunction(
CalledOnceMovableOnlyFunction &&other) noexcept {
wasCalled_ = false;
wasMovedFrom_ = false;
other.wasMovedFrom_ = true;
function_ = std::move(other.function_);
};
CalledOnceMovableOnlyFunction &operator=(
CalledOnceMovableOnlyFunction &&other) noexcept {
assert(
(wasCalled_ || wasMovedFrom_) &&
"`CalledOnceMovableOnlyFunction` is re-assigned before being called.");
wasCalled_ = false;
wasMovedFrom_ = false;
other.wasMovedFrom_ = true;
function_ = std::move(other.function_);
return *this;
}
/*
* Callable.
*/
ReturnT operator()(ArgumentT... args) {
assert(
!wasMovedFrom_ &&
"`CalledOnceMovableOnlyFunction` is called after being moved from.");
assert(
!wasCalled_ &&
"`CalledOnceMovableOnlyFunction` is called more than once.");
wasCalled_ = true;
return function_(args...);
}
};
} // namespace react
} // namespace facebook

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

@ -6,6 +6,7 @@
*/
#include "Utils.h"
#include <stdexcept>
using namespace facebook;

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

@ -8,7 +8,6 @@
#include "event.h"
#include <atomic>
#include <memory>
#include <stdexcept>
namespace facebook {
namespace yoga {

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

@ -11,6 +11,7 @@
#include <vector>
#include <array>
#include <yoga/YGEnums.h>
#include <stdint.h>
struct YGConfig;
struct YGNode;

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

@ -97,7 +97,10 @@ fb_xplat_cxx_binary(
rn_android_library(
name = "rn_codegen_library_java",
srcs = glob(["**/*.java"]),
srcs = glob(
["**/*.java"],
exclude = ["android/gradlePlugin-build/**/*"],
),
visibility = [
"PUBLIC",
],

6
packages/react-native-codegen/android/.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,6 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf

5
packages/react-native-codegen/android/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,5 @@
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build

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

@ -0,0 +1,25 @@
/*
* 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.
*/
buildscript {
repositories {
mavenLocal()
google()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:3.5.3")
}
}
allprojects {
repositories {
mavenLocal()
google()
jcenter()
}
}

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

@ -0,0 +1,19 @@
/*
* 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.
*/
plugins {
id 'java'
id 'application'
}
dependencies {
implementation 'com.squareup:javapoet:1.13.0'
}
application {
mainClassName = 'com.facebook.react.codegen.JavaGeneratorMain'
}

Двоичные данные
packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.jar поставляемый Normal file

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

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

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

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

@ -0,0 +1,14 @@
/*
* 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.
*/
allprojects {
repositories {
mavenLocal()
google()
jcenter()
}
}

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

@ -0,0 +1,23 @@
/*
* 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.
*/
plugins {
id 'java-gradle-plugin'
}
gradlePlugin {
plugins {
greeting {
id = 'com.facebook.react.codegen'
implementationClass = 'com.facebook.react.codegen.plugin.CodegenPlugin'
}
}
}
dependencies {
implementation 'com.squareup:javapoet:1.13.0'
}

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

@ -0,0 +1,51 @@
/*
* 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.react.codegen.generator;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.nio.file.Paths;
import javax.lang.model.element.Modifier;
// TODO: Implement proper generator - this is a sample usage of JavaPoet
public final class JavaGenerator {
private String mSchemaFilePath;
private String mOutputDir;
public JavaGenerator(String schemaFilePath, String outputDir) {
mSchemaFilePath = schemaFilePath;
mOutputDir = outputDir;
}
public void build() throws IOException {
MethodSpec main =
MethodSpec.methodBuilder("main")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(void.class)
.addParameter(String[].class, "args")
.addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
.build();
TypeSpec helloWorld =
TypeSpec.classBuilder("ReactNativeCodegen")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addMethod(main)
.build();
JavaFile javaFile = JavaFile.builder("com.facebook.react.codegen", helloWorld).build();
System.out.println(javaFile.toString());
if (!mOutputDir.isEmpty()) {
javaFile.writeToPath(Paths.get(mOutputDir));
}
}
}

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

@ -0,0 +1,37 @@
/*
* 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.react.codegen.plugin;
import com.facebook.react.codegen.generator.JavaGenerator;
import java.io.IOException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/** A Gradle plugin to enable code generation from JavaScript in Gradle environment. */
public class CodegenPlugin implements Plugin<Project> {
public void apply(final Project project) {
// Register a task
project
.getTasks()
.register(
"generateJava",
task -> {
task.doLast(
s -> {
if (System.getenv("USE_CODEGEN").isEmpty()) {
return;
}
try {
JavaGenerator generator = new JavaGenerator("", "");
generator.build();
} catch (IOException e) {
}
});
});
}
}

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

@ -0,0 +1,10 @@
/*
* 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.
*/
rootProject.name = 'react-native-codegen-gradlePlugin-build'
include(":gradlePlugin")

185
packages/react-native-codegen/android/gradlew поставляемый Executable file
Просмотреть файл

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

104
packages/react-native-codegen/android/gradlew.bat поставляемый Normal file
Просмотреть файл

@ -0,0 +1,104 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

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

@ -0,0 +1,12 @@
/*
* 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.
*/
rootProject.name = 'react-native-codegen'
include(":generator")
includeBuild("gradlePlugin-build")

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

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
* @flow strict
*/
'use strict';

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

@ -9,3 +9,6 @@ include(
":ReactAndroid",
":RNTester:android:app"
)
// Include this to enable codegen Gradle plugin.
includeBuild("packages/react-native-codegen/android")