Merge commit 'c8f571fdad9d632ab618d53520b4365d4e464423' into amgleitman/0.64-merge-head
This commit is contained in:
Коммит
2dfcf658bf
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
Двоичные данные
packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.jar
поставляемый
Normal file
Двоичный файл не отображается.
5
packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.properties
поставляемый
Normal file
5
packages/react-native-codegen/android/gradle/wrapper/gradle-wrapper.properties
поставляемый
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")
|
|
@ -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" "$@"
|
|
@ -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")
|
||||
|
|
Загрузка…
Ссылка в новой задаче