Merge commit 'e261f022fe6a7653b79330f878fed143725f5324' into amgleitman/0.64-merge-2020-mm-dd

This commit is contained in:
Adam Gleitman 2021-08-23 13:58:30 -07:00
Родитель 88fc31603b e261f022fe
Коммит 1618e72a90
143 изменённых файлов: 2513 добавлений и 1656 удалений

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

@ -10,13 +10,12 @@
'use strict';
const React = require('react');
const ReactNative = require('react-native');
const {View} = ReactNative;
const RCTDeviceEventEmitter = require('react-native/Libraries/EventEmitter/RCTDeviceEventEmitter');
const {TestModule} = ReactNative.NativeModules;
import NativeAccessibilityManager from 'react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager';
import invariant from 'invariant';
import NativeAccessibilityManager from 'react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager';
import {DeviceEventEmitter, NativeModules, View} from 'react-native';
import * as React from 'react';
const {TestModule} = NativeModules;
class AccessibilityManagerTest extends React.Component<{...}> {
componentDidMount() {
@ -39,7 +38,7 @@ class AccessibilityManagerTest extends React.Component<{...}> {
accessibilityExtraExtraLarge: 11.0,
accessibilityExtraExtraExtraLarge: 12.0,
});
RCTDeviceEventEmitter.addListener('didUpdateDimensions', update => {
DeviceEventEmitter.addListener('didUpdateDimensions', update => {
TestModule.markTestPassed(update.window.fontScale === 4.0);
});
}

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

@ -17,7 +17,7 @@ const ReactNative = require('react-native');
const {View} = ReactNative;
const {TestModule} = ReactNative.NativeModules;
import type EmitterSubscription from 'react-native/Libraries/vendor/emitter/EmitterSubscription';
import {type EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter';
const reactViewWidth = 101;
const reactViewHeight = 102;
@ -33,7 +33,7 @@ type State = {|
class ReactContentSizeUpdateTest extends React.Component<Props, State> {
_timeoutID: ?TimeoutID = null;
_subscription: ?EmitterSubscription = null;
_subscription: ?EventSubscription = null;
state: State = {
height: reactViewHeight,

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

@ -16,7 +16,7 @@ const ReactNative = require('react-native');
const {View} = ReactNative;
const {TestModule} = ReactNative.NativeModules;
import type EmitterSubscription from 'react-native/Libraries/vendor/emitter/EmitterSubscription';
import {type EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter';
const reactViewWidth = 111;
const reactViewHeight = 222;
@ -31,7 +31,7 @@ type Props = $ReadOnly<{|
|}>;
class SizeFlexibilityUpdateTest extends React.Component<Props> {
_subscription: ?EmitterSubscription = null;
_subscription: ?EventSubscription = null;
UNSAFE_componentWillMount() {
this._subscription = RCTNativeAppEventEmitter.addListener(

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

@ -38,6 +38,15 @@ const API = {
enableQueue: function(): void {
queueConnections = true;
},
getValue: function(
tag: number,
saveValueCallback: (value: number) => void,
): void {
invariant(NativeAnimatedModule, 'Native animated module is not available');
if (NativeAnimatedModule.getValue) {
NativeAnimatedModule.getValue(tag, saveValueCallback);
}
},
disableQueue: function(): void {
invariant(NativeAnimatedModule, 'Native animated module is not available');
queueConnections = false;

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

@ -15,6 +15,7 @@ import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry';
type EndResult = {finished: boolean, ...};
type EndCallback = (result: EndResult) => void;
type SaveValueCallback = (value: number) => void;
export type EventMapping = {|
nativeEventPath: Array<string>,
@ -28,6 +29,7 @@ export type AnimatingNodeConfig = Object;
export interface Spec extends TurboModule {
+createAnimatedNode: (tag: number, config: AnimatedNodeConfig) => void;
+getValue: (tag: number, saveValueCallback: SaveValueCallback) => void;
+startListeningToAnimatedNodeValue: (tag: number) => void;
+stopListeningToAnimatedNodeValue: (tag: number) => void;
+connectAnimatedNodes: (parentTag: number, childTag: number) => void;

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

@ -36,6 +36,7 @@ describe('Native Animated', () => {
beforeEach(() => {
Object.assign(NativeAnimatedModule, {
getValue: jest.fn(),
addAnimatedEventToView: jest.fn(),
connectAnimatedNodes: jest.fn(),
connectAnimatedNodeToView: jest.fn(),
@ -115,6 +116,26 @@ describe('Native Animated', () => {
);
});
it('should save value on unmount', () => {
NativeAnimatedModule.getValue = jest.fn((tag, saveCallback) => {
saveCallback(1);
});
const opacity = new Animated.Value(0);
opacity.__makeNative();
const root = TestRenderer.create(<Animated.View style={{opacity}} />);
const tag = opacity.__getNativeTag();
root.unmount();
expect(NativeAnimatedModule.getValue).toBeCalledWith(
tag,
expect.any(Function),
);
expect(opacity.__getValue()).toBe(1);
});
it('should extract offset', () => {
const opacity = new Animated.Value(0);
opacity.__makeNative();

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

@ -86,6 +86,11 @@ class AnimatedValue extends AnimatedWithChildren {
}
__detach() {
if (this.__isNative) {
NativeAnimatedAPI.getValue(this.__getNativeTag(), value => {
this._value = value;
});
}
this.stopAnimation();
super.__detach();
}

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

@ -10,13 +10,11 @@
'use strict';
const EventEmitter = require('../vendor/emitter/EventEmitter');
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
const invariant = require('invariant');
const logError = require('../Utilities/logError');
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
import logError from '../Utilities/logError';
import EventEmitter from '../vendor/emitter/EventEmitter';
import NativeAppState from './NativeAppState';
import invariant from 'invariant';
/**
* `AppState` can tell you if the app is in the foreground or background,

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

@ -10,11 +10,10 @@
'use strict';
const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter');
import type EmitterSubscription from '../vendor/emitter/EmitterSubscription';
import NativeBugReporting from './NativeBugReporting';
import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter';
import NativeRedBox from '../NativeModules/specs/NativeRedBox';
import {type EventSubscription} from '../vendor/emitter/EventEmitter';
import NativeBugReporting from './NativeBugReporting';
type ExtraData = {[key: string]: string, ...};
type SourceCallback = () => string;
@ -39,8 +38,8 @@ function defaultExtras() {
class BugReporting {
static _extraSources: Map<string, SourceCallback> = new Map();
static _fileSources: Map<string, SourceCallback> = new Map();
static _subscription: ?EmitterSubscription = null;
static _redboxSubscription: ?EmitterSubscription = null;
static _subscription: ?EventSubscription = null;
static _redboxSubscription: ?EventSubscription = null;
static _maybeInit() {
if (!BugReporting._subscription) {

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

@ -10,9 +10,8 @@
'use strict';
const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter');
const UIManager = require('../../ReactNative/UIManager');
import RCTDeviceEventEmitter from '../../EventEmitter/RCTDeviceEventEmitter';
import UIManager from '../../ReactNative/UIManager';
import NativeAccessibilityInfo from './NativeAccessibilityInfo';
const REDUCE_MOTION_EVENT = 'reduceMotionDidChange';

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

@ -10,9 +10,7 @@
'use strict';
const Promise = require('../../Promise');
const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter');
import RCTDeviceEventEmitter from '../../EventEmitter/RCTDeviceEventEmitter';
import NativeAccessibilityManager from './NativeAccessibilityManager';
const CHANGE_EVENT_NAME = {

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

@ -10,14 +10,13 @@
'use strict';
const Platform = require('../../Utilities/Platform');
const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter');
import NativeEventEmitter from '../../EventEmitter/NativeEventEmitter';
import Platform from '../../Utilities/Platform';
import {type EventSubscription} from '../../vendor/emitter/EventEmitter';
import NativeTVNavigationEventEmitter from './NativeTVNavigationEventEmitter';
import type EmitterSubscription from '../../vendor/emitter/EmitterSubscription';
class TVEventHandler {
__nativeTVNavigationEventListener: ?EmitterSubscription = null;
__nativeTVNavigationEventListener: ?EventSubscription = null;
__nativeTVNavigationEventEmitter: ?NativeEventEmitter = null;
enable(component: ?any, callback: Function): void {

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

@ -10,13 +10,11 @@
'use strict';
const LayoutAnimation = require('../../LayoutAnimation/LayoutAnimation');
const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter');
const dismissKeyboard = require('../../Utilities/dismissKeyboard');
const invariant = require('invariant');
import NativeEventEmitter from '../../EventEmitter/NativeEventEmitter';
import LayoutAnimation from '../../LayoutAnimation/LayoutAnimation';
import dismissKeyboard from '../../Utilities/dismissKeyboard';
import NativeKeyboardObserver from './NativeKeyboardObserver';
import invariant from 'invariant';
const KeyboardEventEmitter: NativeEventEmitter = new NativeEventEmitter(
NativeKeyboardObserver,
);

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

@ -18,7 +18,7 @@ const StyleSheet = require('../../StyleSheet/StyleSheet');
const View = require('../View/View');
import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
import type EmitterSubscription from '../../vendor/emitter/EmitterSubscription';
import {type EventSubscription} from '../../vendor/emitter/EventEmitter';
import type {
ViewProps,
ViewLayout,
@ -67,7 +67,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
};
_frame: ?ViewLayout = null;
_subscriptions: Array<EmitterSubscription> = [];
_subscriptions: Array<EventSubscription> = [];
viewRef: {current: React.ElementRef<any> | null, ...};
_initialFrameHeight: number = 0;

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

@ -11,12 +11,12 @@
'use strict';
const Keyboard = require('../Keyboard');
const dismissKeyboard = require('../../../Utilities/dismissKeyboard');
const LayoutAnimation = require('../../../LayoutAnimation/LayoutAnimation');
const NativeEventEmitter = require('../../../EventEmitter/NativeEventEmitter');
const NativeModules = require('../../../BatchedBridge/NativeModules');
const LayoutAnimation = require('../../../LayoutAnimation/LayoutAnimation');
const dismissKeyboard = require('../../../Utilities/dismissKeyboard');
const Keyboard = require('../Keyboard');
import NativeEventEmitter from '../../../EventEmitter/NativeEventEmitter';
jest.mock('../../../LayoutAnimation/LayoutAnimation');

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

@ -10,25 +10,25 @@
'use strict';
const React = require('react');
const Dimensions = require('../Utilities/Dimensions');
const FrameRateLogger = require('../Interaction/FrameRateLogger');
const Keyboard = require('./Keyboard/Keyboard');
const Platform = require('../Utilities/Platform');
const React = require('react');
const ReactNative = require('../Renderer/shims/ReactNative');
const TextInputState = require('./TextInput/TextInputState');
const UIManager = require('../ReactNative/UIManager');
const Platform = require('../Utilities/Platform');
import Commands from './ScrollView/ScrollViewCommands';
const invariant = require('invariant');
const performanceNow = require('fbjs/lib/performanceNow');
import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
import type {PressEvent, ScrollEvent} from '../Types/CoreEventTypes';
import {type EventSubscription} from '../vendor/emitter/EventEmitter';
import type {KeyboardEvent} from './Keyboard/Keyboard';
import typeof ScrollView from './ScrollView/ScrollView';
import type {Props as ScrollViewProps} from './ScrollView/ScrollView';
import type {KeyboardEvent} from './Keyboard/Keyboard';
import type EmitterSubscription from '../vendor/emitter/EmitterSubscription';
import type {HostComponent} from '../Renderer/shims/ReactNativeTypes';
import Commands from './ScrollView/ScrollViewCommands';
/**
* Mixin that can be integrated in order to handle scrolling that plays well
@ -119,10 +119,10 @@ export type State = {|
|};
const ScrollResponderMixin = {
_subscriptionKeyboardWillShow: (null: ?EmitterSubscription),
_subscriptionKeyboardWillHide: (null: ?EmitterSubscription),
_subscriptionKeyboardDidShow: (null: ?EmitterSubscription),
_subscriptionKeyboardDidHide: (null: ?EmitterSubscription),
_subscriptionKeyboardWillShow: (null: ?EventSubscription),
_subscriptionKeyboardWillHide: (null: ?EventSubscription),
_subscriptionKeyboardDidShow: (null: ?EventSubscription),
_subscriptionKeyboardDidHide: (null: ?EventSubscription),
scrollResponderMixinGetInitialState: function(): State {
return {
isTouching: false,

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

@ -10,8 +10,7 @@
'use strict';
const NativeEventEmitter = require('../../EventEmitter/NativeEventEmitter');
import NativeEventEmitter from '../../EventEmitter/NativeEventEmitter';
import NativeStatusBarManagerIOS from './NativeStatusBarManagerIOS';
/**

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

@ -21,6 +21,8 @@ type NativeProps = $ReadOnly<{|
backgroundColor?: ?ColorValue,
|}>;
export default (codegenNativeComponent<NativeProps>(
'RCTInputAccessoryView',
): HostComponent<NativeProps>);
export default (codegenNativeComponent<NativeProps>('InputAccessory', {
interfaceOnly: true,
paperComponentName: 'RCTInputAccessoryView',
excludedPlatforms: ['android'],
}): HostComponent<NativeProps>);

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

@ -285,6 +285,7 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
this.props.useForeground === true,
),
accessible: this.props.accessible !== false,
accessibilityHint: this.props.accessibilityHint,
accessibilityLabel: this.props.accessibilityLabel,
accessibilityRole: this.props.accessibilityRole,
accessibilityState: this.props.accessibilityState,

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

@ -19,6 +19,12 @@ const ReactNativeViewViewConfigAndroid = {
captured: 'onSelectCapture',
},
},
topAssetDidLoad: {
phasedRegistrationNames: {
bubbled: 'onAssetDidLoad',
captured: 'onAssetDidLoadCapture',
},
},
},
directEventTypes: {
topClick: {
@ -57,6 +63,9 @@ const ReactNativeViewViewConfigAndroid = {
topSelectionChange: {
registrationName: 'onSelectionChange',
},
onAssetDidLoad: {
registrationName: 'onAssetDidLoad',
},
},
validAttributes: {
hasTVPreferredFocus: true,

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

@ -10,13 +10,11 @@
'use strict';
const EventEmitter = require('../vendor/emitter/EventEmitter');
const Platform = require('../Utilities/Platform');
const RCTDeviceEventEmitter = require('./RCTDeviceEventEmitter');
const invariant = require('invariant');
import type EmitterSubscription from '../vendor/emitter/EmitterSubscription';
import Platform from '../Utilities/Platform';
import EventEmitter from '../vendor/emitter/EventEmitter';
import {type EventSubscription} from '../vendor/emitter/EventEmitter';
import RCTDeviceEventEmitter from './RCTDeviceEventEmitter';
import invariant from 'invariant';
type NativeModule = {
+addListener: (eventType: string) => void,
@ -46,7 +44,7 @@ class NativeEventEmitter extends EventEmitter {
eventType: string,
listener: Function,
context: ?Object,
): EmitterSubscription {
): EventSubscription {
if (this._nativeModule != null) {
this._nativeModule.addListener(eventType);
}
@ -62,7 +60,7 @@ class NativeEventEmitter extends EventEmitter {
super.removeAllListeners(eventType);
}
removeSubscription(subscription: EmitterSubscription) {
removeSubscription(subscription: EventSubscription) {
if (this._nativeModule != null) {
this._nativeModule.removeListeners(1);
}

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

@ -10,10 +10,9 @@
'use strict';
const EventEmitter = require('../vendor/emitter/EventEmitter');
const EventSubscriptionVendor = require('../vendor/emitter/EventSubscriptionVendor');
import type EmitterSubscription from '../vendor/emitter/EmitterSubscription';
import EventEmitter from '../vendor/emitter/EventEmitter';
import type EmitterSubscription from '../vendor/emitter/_EmitterSubscription';
import EventSubscriptionVendor from '../vendor/emitter/_EventSubscriptionVendor';
function checkNativeEventModule(eventType: ?string) {
if (eventType) {

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

@ -10,7 +10,7 @@
'use strict';
const RCTDeviceEventEmitter = require('./RCTDeviceEventEmitter');
import RCTDeviceEventEmitter from './RCTDeviceEventEmitter';
/**
* Deprecated - subclass NativeEventEmitter to create granular event modules instead of

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

@ -10,8 +10,8 @@
'use strict';
const EventEmitter = require('../../vendor/emitter/EventEmitter');
const RCTDeviceEventEmitter = require('../RCTDeviceEventEmitter');
import EventEmitter from '../../vendor/emitter/EventEmitter';
import RCTDeviceEventEmitter from '../RCTDeviceEventEmitter';
/**
* Mock the NativeEventEmitter as a normal JS EventEmitter.

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

@ -233,6 +233,10 @@ namespace facebook {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "createAnimatedNode", @selector(createAnimatedNode:config:), args, count);
}
static facebook::jsi::Value __hostFunction_NativeAnimatedModuleSpecJSI_getValue(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "getValue", @selector(getValue:saveValueCallback:), args, count);
}
static facebook::jsi::Value __hostFunction_NativeAnimatedModuleSpecJSI_startListeningToAnimatedNodeValue(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "startListeningToAnimatedNodeValue", @selector(startListeningToAnimatedNodeValue:), args, count);
}
@ -312,6 +316,9 @@ namespace facebook {
methodMap_["createAnimatedNode"] = MethodMetadata {2, __hostFunction_NativeAnimatedModuleSpecJSI_createAnimatedNode};
methodMap_["getValue"] = MethodMetadata {2, __hostFunction_NativeAnimatedModuleSpecJSI_getValue};
methodMap_["startListeningToAnimatedNodeValue"] = MethodMetadata {1, __hostFunction_NativeAnimatedModuleSpecJSI_startListeningToAnimatedNodeValue};

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

@ -276,6 +276,8 @@ namespace JS {
- (void)createAnimatedNode:(double)tag
config:(NSDictionary *)config;
- (void)getValue:(double)tag
saveValueCallback:(RCTResponseSenderBlock)saveValueCallback;
- (void)startListeningToAnimatedNodeValue:(double)tag;
- (void)stopListeningToAnimatedNodeValue:(double)tag;
- (void)connectAnimatedNodes:(double)parentTag

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

@ -11,13 +11,14 @@
'use strict';
const BatchedBridge = require('../BatchedBridge/BatchedBridge');
const EventEmitter = require('../vendor/emitter/EventEmitter');
const TaskQueue = require('./TaskQueue');
const infoLog = require('../Utilities/infoLog');
const invariant = require('invariant');
const keyMirror = require('fbjs/lib/keyMirror');
import EventEmitter from '../vendor/emitter/EventEmitter';
export type Handle = number;
import type {Task} from './TaskQueue';

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

@ -10,13 +10,11 @@
'use strict';
const InteractionManager = require('../Interaction/InteractionManager');
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
const Platform = require('../Utilities/Platform');
const invariant = require('invariant');
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
import InteractionManager from '../Interaction/InteractionManager';
import Platform from '../Utilities/Platform';
import NativeLinking from './NativeLinking';
import invariant from 'invariant';
/**
* `Linking` gives you a general interface to interact with both incoming

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

@ -11,7 +11,6 @@
'use strict';
const AppContainer = require('../ReactNative/AppContainer');
const {RootTagContext} = require('../ReactNative/RootTag');
const I18nManager = require('../ReactNative/I18nManager');
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
import NativeModalManager from './NativeModalManager';
@ -22,12 +21,14 @@ const ScrollView = require('../Components/ScrollView/ScrollView');
const StyleSheet = require('../StyleSheet/StyleSheet');
const View = require('../Components/View/View');
import type {RootTag} from '../ReactNative/RootTag';
const {RootTagContext} = require('../ReactNative/RootTag');
import type {ViewProps} from '../Components/View/ViewPropTypes';
import type {DirectEventHandler} from '../Types/CodegenTypes';
import type EmitterSubscription from '../vendor/emitter/EmitterSubscription';
import RCTModalHostView from './RCTModalHostViewNativeComponent';
import {VirtualizedListContextResetter} from '../Lists/VirtualizedListContext.js';
import type {RootTag} from '../ReactNative/RootTag';
import type {DirectEventHandler} from '../Types/CodegenTypes';
import {type EventSubscription} from '../vendor/emitter/EventEmitter';
import RCTModalHostView from './RCTModalHostViewNativeComponent';
const ModalEventEmitter =
Platform.OS === 'ios' && NativeModalManager != null
@ -161,7 +162,7 @@ class Modal extends React.Component<Props> {
static contextType: React.Context<RootTag> = RootTagContext;
_identifier: number;
_eventSubscription: ?EmitterSubscription;
_eventSubscription: ?EventSubscription;
constructor(props: Props) {
super(props);

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

@ -216,6 +216,12 @@ RCT_EXPORT_METHOD(removeAnimatedEventFromView:(double)viewTag
}];
}
RCT_EXPORT_METHOD(getValue:(double)nodeTag saveCallback:(RCTResponseSenderBlock)saveCallback) {
[self addOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) {
[nodesManager getValue:[NSNumber numberWithDouble:nodeTag] saveCallback:saveCallback];
}];
}
#pragma mark -- Batch handling
- (void)addOperationBlock:(AnimatedOperation)operation
@ -300,7 +306,6 @@ RCT_EXPORT_METHOD(removeAnimatedEventFromView:(double)viewTag
operation(self->_nodesManager);
}
}];
[uiManager addUIBlock:^(__unused RCTUIManager *manager, __unused NSDictionary<NSNumber *, RCTPlatformView *> *viewRegistry) { // TODO(macOS ISS#3536887)
for (AnimatedOperation operation in operations) {
operation(self->_nodesManager);

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

@ -22,6 +22,9 @@
- (BOOL)isNodeManagedByFabric:(nonnull NSNumber *)tag;
- (void)getValue:(nonnull NSNumber *)nodeTag
saveCallback:(nullable RCTResponseSenderBlock)saveCallback;
// graph
- (void)createAnimatedNode:(nonnull NSNumber *)tag

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

@ -242,6 +242,17 @@ static NSString *RCTNormalizeAnimatedEventName(NSString *eventName)
[valueNode extractOffset];
}
- (void)getValue:(NSNumber *)nodeTag saveCallback:(RCTResponseSenderBlock)saveCallback
{
RCTAnimatedNode *node = _animationNodes[nodeTag];
if (![node isKindOfClass:[RCTValueAnimatedNode class]]) {
RCTLogError(@"Not a value node.");
return;
}
RCTValueAnimatedNode *valueNode = (RCTValueAnimatedNode *)node;;
saveCallback(@[@(valueNode.value)]);
}
#pragma mark -- Drivers
- (void)startAnimatingNode:(nonnull NSNumber *)animationId

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

@ -12,10 +12,9 @@
// Do not require the native RCTNetworking module directly! Use this wrapper module instead.
// It will add the necessary requestId, so that you don't have to generate it yourself.
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
const convertRequestBody = require('./convertRequestBody');
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
import NativeNetworkingAndroid from './NativeNetworkingAndroid';
import convertRequestBody from './convertRequestBody';
import type {RequestBody} from './convertRequestBody';
type Header = [string, string];

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

@ -10,12 +10,10 @@
'use strict';
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
const convertRequestBody = require('./convertRequestBody');
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
import NativeNetworkingIOS from './NativeNetworkingIOS';
import type {NativeResponseType} from './XMLHttpRequest';
import convertRequestBody from './convertRequestBody';
import type {RequestBody} from './convertRequestBody';
class RCTNetworking extends NativeEventEmitter {

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

@ -10,10 +10,10 @@
'use strict';
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
import {Platform} from 'react-native'; // TODO(macOS GH#774)
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
import NativePushNotificationManagerIOS from './NativePushNotificationManagerIOS';
const invariant = require('invariant');
import invariant from 'invariant';
const PushNotificationEmitter = new NativeEventEmitter(
NativePushNotificationManagerIOS,

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

@ -10,13 +10,13 @@
'use strict';
const EmitterSubscription = require('../vendor/emitter/EmitterSubscription');
const PropTypes = require('prop-types');
const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter');
const React = require('react');
import View from '../Components/View/View';
import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter';
import StyleSheet from '../StyleSheet/StyleSheet';
import {type EventSubscription} from '../vendor/emitter/EventEmitter';
import {RootTagContext, createRootTag} from './RootTag';
const StyleSheet = require('../StyleSheet/StyleSheet');
const View = require('../Components/View/View');
import PropTypes from 'prop-types';
import * as React from 'react';
type Context = {rootTag: number, ...};
@ -43,7 +43,7 @@ class AppContainer extends React.Component<Props, State> {
hasError: false,
};
_mainRef: ?React.ElementRef<typeof View>;
_subscription: ?EmitterSubscription = null;
_subscription: ?EventSubscription = null;
static getDerivedStateFromError: any = undefined;

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

@ -10,11 +10,9 @@
'use strict';
const RCTDeviceEventEmitter = require('../EventEmitter/RCTDeviceEventEmitter');
const invariant = require('invariant');
import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter';
import NativeSettingsManager from './NativeSettingsManager';
import invariant from 'invariant';
const subscriptions: Array<{
keys: Array<string>,

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

@ -69,6 +69,7 @@ const viewConfig = {
onInlineViewLayout: true,
dataDetectorType: true,
tooltip: true,
android_hyphenationFrequency: true,
},
directEventTypes: {
topTextLayout: {

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

@ -45,6 +45,8 @@ NS_ASSUME_NONNULL_BEGIN
// it's declared here only to conform to the interface.
@property (nonatomic, assign) BOOL caretHidden;
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;
#if TARGET_OS_OSX // [TODO(macOS GH#774)
@property (nonatomic, assign) BOOL scrollEnabled;
@property (nonatomic, strong, nullable) RCTUIColor *selectionColor; // TODO(OSS Candidate ISS#2710739)

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

@ -55,6 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, assign) UITextFieldViewMode clearButtonMode;
#endif // TODO(macOS GH#774)
@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;
// This protocol disallows direct access to `selectedTextRange` property because
// unwise usage of it can break the `delegate` behavior. So, we always have to

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

@ -42,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (assign, getter=isEditable) BOOL editable;
#endif // ]TODO(macOS GH#774)
@property (nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
@property (nonatomic, strong, nullable) NSString *inputAccessoryViewID;
#if TARGET_OS_OSX // [TODO(macOS GH#774)
@property (nonatomic, copy, nullable) NSString *text;

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

@ -57,6 +57,18 @@ export type TextProps = $ReadOnly<{|
* See https://reactnative.dev/docs/text.html#allowfontscaling
*/
allowFontScaling?: ?boolean,
/**
* Set hyphenation strategy on Android.
*
*/
android_hyphenationFrequency?: ?(
| 'normal'
| 'none'
| 'full'
| 'high'
| 'balanced'
),
children?: ?Node,
/**

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

@ -10,18 +10,16 @@
'use strict';
const Blob = require('../Blob/Blob');
const BlobManager = require('../Blob/BlobManager');
const EventTarget = require('event-target-shim');
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
const WebSocketEvent = require('./WebSocketEvent');
const base64 = require('base64-js');
const binaryToBase64 = require('../Utilities/binaryToBase64');
const invariant = require('invariant');
import type EventSubscription from '../vendor/emitter/EventSubscription';
import Blob from '../Blob/Blob';
import BlobManager from '../Blob/BlobManager';
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
import binaryToBase64 from '../Utilities/binaryToBase64';
import {type EventSubscription} from '../vendor/emitter/EventEmitter';
import NativeWebSocketModule from './NativeWebSocketModule';
import WebSocketEvent from './WebSocketEvent';
import base64 from 'base64-js';
import EventTarget from 'event-target-shim';
import invariant from 'invariant';
type ArrayBufferView =
| Int8Array

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

@ -9,11 +9,9 @@
'use strict';
const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter';
import NativeWebSocketModule from './NativeWebSocketModule';
const base64 = require('base64-js');
import base64 from 'base64-js';
const originalRCTWebSocketConnect = NativeWebSocketModule.connect;
const originalRCTWebSocketSend = NativeWebSocketModule.send;

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

@ -580,16 +580,7 @@ if (global.nativeLoggingHook) {
const reactNativeMethod = console[methodName];
if (originalConsole[methodName]) {
console[methodName] = function() {
// TODO(T43930203): remove this special case once originalConsole.assert properly checks
// the condition
if (methodName === 'assert') {
if (!arguments[0] && originalConsole.hasOwnProperty('assert')) {
// TODO(macOS GH#774)
originalConsole.assert(...arguments);
}
} else {
originalConsole[methodName](...arguments);
}
originalConsole[methodName](...arguments);
reactNativeMethod.apply(console, arguments);
};
}

220
Libraries/vendor/emitter/EventEmitter.js поставляемый
Просмотреть файл

@ -4,225 +4,17 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @noflow
* @typecheck
*/
'use strict';
const EmitterSubscription = require('./EmitterSubscription');
const EventSubscriptionVendor = require('./EventSubscriptionVendor');
// $FlowFixMe - EventEmitter Type Safety
const EventEmitter = require('./_EventEmitter');
const invariant = require('invariant');
export default EventEmitter;
const sparseFilterPredicate = () => true;
/**
* @class EventEmitter
* @description
* An EventEmitter is responsible for managing a set of listeners and publishing
* events to them when it is told that such events happened. In addition to the
* data for the given event it also sends a event control object which allows
* the listeners/handlers to prevent the default behavior of the given event.
*
* The emitter is designed to be generic enough to support all the different
* contexts in which one might want to emit events. It is a simple multicast
* mechanism on top of which extra functionality can be composed. For example, a
* more advanced emitter may use an EventHolder and EventFactory.
*/
class EventEmitter {
_subscriber: EventSubscriptionVendor;
_currentSubscription: ?EmitterSubscription;
/**
* @constructor
*
* @param {EventSubscriptionVendor} subscriber - Optional subscriber instance
* to use. If omitted, a new subscriber will be created for the emitter.
*/
constructor(subscriber: ?EventSubscriptionVendor) {
this._subscriber = subscriber || new EventSubscriptionVendor();
}
/**
* Adds a listener to be invoked when events of the specified type are
* emitted. An optional calling context may be provided. The data arguments
* emitted will be passed to the listener function.
*
* TODO: Annotate the listener arg's type. This is tricky because listeners
* can be invoked with varargs.
*
* @param {string} eventType - Name of the event to listen to
* @param {function} listener - Function to invoke when the specified event is
* emitted
* @param {*} context - Optional context object to use when invoking the
* listener
*/
addListener(
eventType: string,
listener: Function,
context: ?Object,
): EmitterSubscription {
return (this._subscriber.addSubscription(
eventType,
new EmitterSubscription(this, this._subscriber, listener, context),
): any);
}
/**
* Similar to addListener, except that the listener is removed after it is
* invoked once.
*
* @param {string} eventType - Name of the event to listen to
* @param {function} listener - Function to invoke only once when the
* specified event is emitted
* @param {*} context - Optional context object to use when invoking the
* listener
*/
once(
eventType: string,
listener: Function,
context: ?Object,
): EmitterSubscription {
return this.addListener(eventType, (...args) => {
this.removeCurrentListener();
listener.apply(context, args);
});
}
/**
* Removes all of the registered listeners, including those registered as
* listener maps.
*
* @param {?string} eventType - Optional name of the event whose registered
* listeners to remove
*/
removeAllListeners(eventType: ?string) {
this._subscriber.removeAllSubscriptions(eventType);
}
/**
* Provides an API that can be called during an eventing cycle to remove the
* last listener that was invoked. This allows a developer to provide an event
* object that can remove the listener (or listener map) during the
* invocation.
*
* If it is called when not inside of an emitting cycle it will throw.
*
* @throws {Error} When called not during an eventing cycle
*
* @example
* var subscription = emitter.addListenerMap({
* someEvent: function(data, event) {
* console.log(data);
* emitter.removeCurrentListener();
* }
* });
*
* emitter.emit('someEvent', 'abc'); // logs 'abc'
* emitter.emit('someEvent', 'def'); // does not log anything
*/
removeCurrentListener() {
invariant(
!!this._currentSubscription,
'Not in an emitting cycle; there is no current subscription',
);
this.removeSubscription(this._currentSubscription);
}
/**
* Removes a specific subscription. Called by the `remove()` method of the
* subscription itself to ensure any necessary cleanup is performed.
*/
removeSubscription(subscription: EmitterSubscription) {
invariant(
subscription.emitter === this,
'Subscription does not belong to this emitter.',
);
this._subscriber.removeSubscription(subscription);
}
/**
* Returns an array of listeners that are currently registered for the given
* event.
*
* @param {string} eventType - Name of the event to query
* @returns {array}
*/
listeners(eventType: string): [EmitterSubscription] {
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
return subscriptions
? subscriptions
// We filter out missing entries because the array is sparse.
// "callbackfn is called only for elements of the array which actually
// exist; it is not called for missing elements of the array."
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.filter
.filter(sparseFilterPredicate)
.map(subscription => subscription.listener)
: [];
}
/**
* Emits an event of the given type with the given data. All handlers of that
* particular type will be notified.
*
* @param {string} eventType - Name of the event to emit
* @param {...*} Arbitrary arguments to be passed to each registered listener
*
* @example
* emitter.addListener('someEvent', function(message) {
* console.log(message);
* });
*
* emitter.emit('someEvent', 'abc'); // logs 'abc'
*/
emit(eventType: string) {
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (let i = 0, l = subscriptions.length; i < l; i++) {
const subscription = subscriptions[i];
// The subscription may have been removed during this event loop.
if (subscription && subscription.listener) {
this._currentSubscription = subscription;
subscription.listener.apply(
subscription.context,
Array.prototype.slice.call(arguments, 1),
);
}
}
this._currentSubscription = null;
}
}
/**
* Removes the given listener for event of specific type.
*
* @param {string} eventType - Name of the event to emit
* @param {function} listener - Function to invoke when the specified event is
* emitted
*
* @example
* emitter.removeListener('someEvent', function(message) {
* console.log(message);
* }); // removes the listener if already registered
*
*/
removeListener(eventType: String, listener) {
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (let i = 0, l = subscriptions.length; i < l; i++) {
const subscription = subscriptions[i];
// The subscription may have been removed during this event loop.
// its listener matches the listener in method parameters
if (subscription && subscription.listener === listener) {
subscription.remove();
}
}
}
}
export interface EventSubscription {
remove(): void;
}
module.exports = EventEmitter;

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

@ -10,10 +10,9 @@
'use strict';
const EventSubscription = require('./EventSubscription');
import type EventEmitter from './EventEmitter';
import type EventSubscriptionVendor from './EventSubscriptionVendor';
import EventSubscription from './_EventSubscription';
import type EventSubscriptionVendor from './_EventSubscriptionVendor';
/**
* EmitterSubscription represents a subscription with listener and context data.

175
Libraries/vendor/emitter/_EventEmitter.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,175 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @noflow
* @typecheck
*/
'use strict';
const invariant = require('invariant');
import EmitterSubscription from './_EmitterSubscription';
import EventSubscriptionVendor from './_EventSubscriptionVendor';
const sparseFilterPredicate = () => true;
/**
* @class EventEmitter
* @description
* An EventEmitter is responsible for managing a set of listeners and publishing
* events to them when it is told that such events happened. In addition to the
* data for the given event it also sends a event control object which allows
* the listeners/handlers to prevent the default behavior of the given event.
*
* The emitter is designed to be generic enough to support all the different
* contexts in which one might want to emit events. It is a simple multicast
* mechanism on top of which extra functionality can be composed. For example, a
* more advanced emitter may use an EventHolder and EventFactory.
*/
class EventEmitter {
_subscriber: EventSubscriptionVendor;
/**
* @constructor
*
* @param {EventSubscriptionVendor} subscriber - Optional subscriber instance
* to use. If omitted, a new subscriber will be created for the emitter.
*/
constructor(subscriber: ?EventSubscriptionVendor) {
this._subscriber = subscriber || new EventSubscriptionVendor();
}
/**
* Adds a listener to be invoked when events of the specified type are
* emitted. An optional calling context may be provided. The data arguments
* emitted will be passed to the listener function.
*
* TODO: Annotate the listener arg's type. This is tricky because listeners
* can be invoked with varargs.
*
* @param {string} eventType - Name of the event to listen to
* @param {function} listener - Function to invoke when the specified event is
* emitted
* @param {*} context - Optional context object to use when invoking the
* listener
*/
addListener(
eventType: string,
listener: Function,
context: ?Object,
): EmitterSubscription {
return (this._subscriber.addSubscription(
eventType,
new EmitterSubscription(this, this._subscriber, listener, context),
): any);
}
/**
* Removes all of the registered listeners, including those registered as
* listener maps.
*
* @param {?string} eventType - Optional name of the event whose registered
* listeners to remove
*/
removeAllListeners(eventType: ?string) {
this._subscriber.removeAllSubscriptions(eventType);
}
/**
* Removes a specific subscription. Called by the `remove()` method of the
* subscription itself to ensure any necessary cleanup is performed.
*/
removeSubscription(subscription: EmitterSubscription) {
invariant(
subscription.emitter === this,
'Subscription does not belong to this emitter.',
);
this._subscriber.removeSubscription(subscription);
}
/**
* Returns an array of listeners that are currently registered for the given
* event.
*
* @param {string} eventType - Name of the event to query
* @returns {array}
*/
listeners(eventType: string): [EmitterSubscription] {
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
return subscriptions
? subscriptions
// We filter out missing entries because the array is sparse.
// "callbackfn is called only for elements of the array which actually
// exist; it is not called for missing elements of the array."
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.filter
.filter(sparseFilterPredicate)
.map(subscription => subscription.listener)
: [];
}
/**
* Emits an event of the given type with the given data. All handlers of that
* particular type will be notified.
*
* @param {string} eventType - Name of the event to emit
* @param {...*} Arbitrary arguments to be passed to each registered listener
*
* @example
* emitter.addListener('someEvent', function(message) {
* console.log(message);
* });
*
* emitter.emit('someEvent', 'abc'); // logs 'abc'
*/
emit(eventType: string) {
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (let i = 0, l = subscriptions.length; i < l; i++) {
const subscription = subscriptions[i];
// The subscription may have been removed during this event loop.
if (subscription && subscription.listener) {
subscription.listener.apply(
subscription.context,
Array.prototype.slice.call(arguments, 1),
);
}
}
}
}
/**
* Removes the given listener for event of specific type.
*
* @param {string} eventType - Name of the event to emit
* @param {function} listener - Function to invoke when the specified event is
* emitted
*
* @example
* emitter.removeListener('someEvent', function(message) {
* console.log(message);
* }); // removes the listener if already registered
*
*/
removeListener(eventType: String, listener) {
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
for (let i = 0, l = subscriptions.length; i < l; i++) {
const subscription = subscriptions[i];
// The subscription may have been removed during this event loop.
// its listener matches the listener in method parameters
if (subscription && subscription.listener === listener) {
subscription.remove();
}
}
}
}
}
module.exports = EventEmitter;

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

@ -10,7 +10,7 @@
'use strict';
import type EventSubscriptionVendor from './EventSubscriptionVendor';
import type EventSubscriptionVendor from './_EventSubscriptionVendor';
/**
* EventSubscription represents a subscription to a particular event. It can

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

@ -12,7 +12,7 @@
const invariant = require('invariant');
import type EventSubscription from './EventSubscription';
import type EventSubscription from './_EventSubscription';
/**
* EventSubscriptionVendor stores a set of EventSubscriptions that are

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

@ -524,8 +524,8 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0
FBLazyVector: 98b31cc648baaf777f631c1faa014adfb111dd36
FBReactNativeSpec: bf2e6b17d4cfb71670a7eb78db955af21e923d76
FBLazyVector: 25db8fc930c080720dd9f1d1a26d539ce9515858
FBReactNativeSpec: 357b56d66b8d511a9f812b4c630bd4966a433371
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
@ -536,34 +536,34 @@ SPEC CHECKSUMS:
glog: 789873d01e4b200777d0a09bc23d548446758699
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7
RCTRequired: a6c49a02ff5189dfeaf791a51d21064766344e72
RCTTypeSafety: 6bb50d00867266b0d061b94f5e225b9945882688
React: 78f1070302eae565a18c64e9d8052ed223768640
React-ART: a5ab7ec5b4576cf43e262809a93d42ee7e8413bf
React-callinvoker: d223e8b29d68bc2238b878501861d8ba24fce52e
React-Core: af3201d391ab6aa22eb000f2e6a0e206f2c3888c
React-CoreModules: 5cd8929ac73b3f5606cf3b5b0821ece53eafff8b
React-cxxreact: 4fa8629ade061a82ea45de0c4b87d479e48adb68
React-jsi: dc6f1e92c022648c355c23e1949cff6607f9cbfd
React-jsiexecutor: 3b7454c42768f05ed3cc37e6f895178763976b9c
React-jsinspector: d2982fce9882b572b4d09460c001697b0cbcac26
React-perflogger: fb60383b80547c8ce8fa5d8984447b09db21c5cd
React-RCTActionSheet: 3b37e04729f1cbc38167daa61c0a56ec88d80c98
React-RCTAnimation: b25e66f6f885a28a329ca4cd7f1756f7e7955b9f
React-RCTBlob: 347583bec23dfc93b38efe963c02083ba6cf4e11
React-RCTImage: 33b8c6a26efde67f1a37422778d847b1970fc178
React-RCTLinking: 25f85db00b40a22daa03bb0423a029329a545d44
React-RCTNetwork: 4acf13ffdc4b65468838d833256a69c7f428281e
React-RCTPushNotification: de80429639189142d77281feb5f72c68b1c54766
React-RCTSettings: a454a15306ce3db6e3c1b101b0b3cc5b79786896
React-RCTTest: a407d26fd93dce440fd9b991936f2ebb01535244
React-RCTText: 4d6d446fb541e5d851bc37b218da70938a29bfaf
React-RCTVibration: 27e8099fa8ece2cc97f2abd016c1b06aacb75912
React-runtimeexecutor: 8e9720ed1a7c405f81bd399f2a3247bbcabe1d04
RCTRequired: ce43f9f9167af58d0e1eecf5605634ab016faa81
RCTTypeSafety: c9b0498fb46d5d1d756e0ce90dd5e60f1b9d5cdd
React: 9a7fd7a316d91eaabfb9b6fbe3456d873e1d92b2
React-ART: c2a752357958d214b16806c18fd812e3eda5165e
React-callinvoker: 66b62bab1170e0359d46a8af0cb61a9a1a8d18ad
React-Core: 312e62d070297a0cf4c693eb9400145149b1fc70
React-CoreModules: 68d668bfd30a500e49c83c68e2fc75524f2437f8
React-cxxreact: 6e2e98c6b87bc02437806a9498c582a03a10c9f5
React-jsi: 827382a7da620a02cb890accfcf84de279f272a6
React-jsiexecutor: dbc72f3190c3f3bf7d2ac548ce17e12d357e122b
React-jsinspector: 320d5cb76361b00a6a87a8b5a67280c200712604
React-perflogger: 0cac631583b97716913aafd5d5c07ac133bab771
React-RCTActionSheet: c15c33157199c398d405a5cbc2715d9dba17bbf8
React-RCTAnimation: bffa5450d36cae700b6c97bfdd617986810b6f33
React-RCTBlob: 169d4c1f011c5fe60f43cbde36f25391c5bd62a7
React-RCTImage: 3a129461152c25115f67a3052e086b8277c36938
React-RCTLinking: 2f4d467f6449bfa6f35ef108ea4eada0c110e020
React-RCTNetwork: 66bdde9026a6fe29b06b6027b847de96153653a7
React-RCTPushNotification: c2b605a89e385917bb764017d0e8e5c6d4f4a206
React-RCTSettings: 8d536a656c3d2f34ea155d24244488a0c39ec3b2
React-RCTTest: 991feac2784e473e8b466091259cefe6d33bc72f
React-RCTText: 6be029a3b38a2b98f875b84a4bd182eebd048218
React-RCTVibration: 655e32ab1393718662b8a6f75eef9f3d2ceedf96
React-runtimeexecutor: b529b2ffeac2f15b775a37226471a2523a3f7844
React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817
React-TurboModuleCxx-WinRTPort: 78a8f1fb00ab240213f0c1937934182774ec1d8c
ReactCommon: 733e0f7149c889701ad3992f82c1bda8b21edcb7
Yoga: 4b69710d7e082acfb7daca42ceadd79d196a67cd
React-TurboModuleCxx-WinRTPort: 29b59397f335c90defd1c74eaf0982ccd13c52be
ReactCommon: 989cfe7b74513b6bed09cf75e733bc631ec963c7
Yoga: ba2f886e24a03fa7dad871b727b5de2a7205dd8a
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 7d43a928a9b9ad27329da110adbfadd923a39ba8

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

@ -866,6 +866,23 @@ static id RCTPropChecker(NSString *prop, NSNumber *value)
[_uiManager verify];
}
- (void) testGetValue
{
__block NSInteger saveValueCallbackCalls = 0;
NSNumber *nodeTag = @100;
[_nodesManager createAnimatedNode:nodeTag
config:@{@"type": @"value", @"value": @1, @"offset": @0}];
RCTResponseSenderBlock saveValueCallback = ^(NSArray *response) {
saveValueCallbackCalls++;
XCTAssertEqualObjects(response, @[@1]);
};
XCTAssertEqual(saveValueCallbackCalls, 0);
[_nodesManager getValue:nodeTag saveCallback:saveValueCallback];
XCTAssertEqual(saveValueCallbackCalls, 1);
}
/**
* Creates a following graph of nodes:
* Value(3, initialValue) ----> Style(4) ---> Props(5) ---> View(viewTag)

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

@ -335,6 +335,115 @@ exports.examples = [
);
},
},
{
title: 'Moving box example',
description: ('Click arrow buttons to move the box.' +
'Then hide the box and reveal it again.' +
'After that the box position will reset to initial position.': string),
render: (): React.Node => {
const containerWidth = 200;
const boxSize = 50;
const movingBoxStyles = StyleSheet.create({
container: {
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
backgroundColor: '#fff',
padding: 30,
},
boxContainer: {
backgroundColor: '#d3d3d3',
height: boxSize,
width: containerWidth,
},
box: {
width: boxSize,
height: boxSize,
margin: 0,
},
buttonsContainer: {
marginTop: 20,
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
width: containerWidth,
},
});
type Props = $ReadOnly<{||}>;
type State = {|boxVisible: boolean|};
class MovingBoxExample extends React.Component<Props, State> {
x: Animated.Value;
constructor(props) {
super(props);
this.x = new Animated.Value(0);
this.state = {
boxVisible: true,
};
}
render() {
const {boxVisible} = this.state;
const toggleText = boxVisible ? 'Hide' : 'Show';
return (
<View style={movingBoxStyles.container}>
{this.renderBox()}
<View style={movingBoxStyles.buttonsContainer}>
<RNTesterButton onPress={() => this.moveTo(0)}>
{'<-'}
</RNTesterButton>
<RNTesterButton onPress={this.toggleVisibility}>
{toggleText}
</RNTesterButton>
<RNTesterButton
onPress={() => this.moveTo(containerWidth - boxSize)}>
{'->'}
</RNTesterButton>
</View>
</View>
);
}
renderBox = () => {
if (this.state.boxVisible) {
const horizontalLocation = {transform: [{translateX: this.x}]};
return (
<View style={movingBoxStyles.boxContainer}>
<Animated.View
style={[
styles.content,
movingBoxStyles.box,
horizontalLocation,
]}
/>
</View>
);
} else {
return (
<View style={movingBoxStyles.boxContainer}>
<Text>The box view is not being rendered</Text>
</View>
);
}
};
moveTo = x => {
Animated.timing(this.x, {
toValue: x,
duration: 1000,
useNativeDriver: true,
}).start();
};
toggleVisibility = () => {
const {boxVisible} = this.state;
this.setState({boxVisible: !boxVisible});
};
}
return <MovingBoxExample />;
},
},
{
title: 'Continuous Interactions',
description: ('Gesture events, chaining, 2D ' +

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

@ -14,10 +14,10 @@ const React = require('react');
const {DeviceEventEmitter, Text, View} = require('react-native');
import type EmitterSubscription from '../../../../Libraries/vendor/emitter/EmitterSubscription';
import {type EventSubscription} from '../../../../Libraries/vendor/emitter/EventEmitter';
class OrientationChangeExample extends React.Component<{...}, $FlowFixMeState> {
_orientationSubscription: EmitterSubscription;
_orientationSubscription: EventSubscription;
state = {
currentOrientation: '',

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

@ -210,7 +210,10 @@ function FallbackColorsExample() {
color: PlatformColor('bogus', '@color/catalyst_redbox_background'),
};
} else {
throw 'Unexpected Platform.OS: ' + Platform.OS;
color = {
label: 'Unexpected Platform.OS: ' + Platform.OS,
color: 'red',
};
}
return (
@ -312,6 +315,7 @@ function VariantColorsExample() {
ios: "DynamicColorIOS({light: 'red', dark: 'blue'})",
android: "PlatformColor('?attr/colorAccent')",
macos: "DynamicColorMacOS({light: 'red', dark: 'blue'})",
default: 'Unexpected Platform.OS: ' + Platform.OS,
})
// ]TODO(OSS Candidate ISS#2710739)
}
@ -326,7 +330,9 @@ function VariantColorsExample() {
Platform.OS === 'macos'
? DynamicColorMacOS({light: 'red', dark: 'blue'})
: // ]TODO(macOS GH#774)
PlatformColor('?attr/colorAccent'),
Platform.OS === 'android'
? PlatformColor('?attr/colorAccent')
: 'red',
}}
/>
</View>

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

@ -146,6 +146,7 @@ class AdjustingFontSize extends React.Component<
<Text
adjustsFontSizeToFit={true}
numberOfLines={4}
android_hyphenationFrequency="normal"
style={{fontSize: 20, marginVertical: 6}}>
{'Multiline text component shrinking is supported, watch as this reeeeaaaally loooooong teeeeeeext grooooows and then shriiiinks as you add text to me! ioahsdia soady auydoa aoisyd aosdy ' +
' ' +
@ -207,6 +208,28 @@ class TextExample extends React.Component<{...}> {
going to the next line.
</Text>
</RNTesterBlock>
<RNTesterBlock title="Hyphenation">
<Text android_hyphenationFrequency="normal">
<Text style={{color: 'red'}}>Normal: </Text>
WillHaveAnHyphenWhenBreakingForNewLine
</Text>
<Text android_hyphenationFrequency="none">
<Text style={{color: 'red'}}>None: </Text>
WillNotHaveAnHyphenWhenBreakingForNewLine
</Text>
<Text android_hyphenationFrequency="full">
<Text style={{color: 'red'}}>Full: </Text>
WillHaveAnHyphenWhenBreakingForNewLine
</Text>
<Text android_hyphenationFrequency="high">
<Text style={{color: 'red'}}>High: </Text>
WillHaveAnHyphenWhenBreakingForNewLine
</Text>
<Text android_hyphenationFrequency="balanced">
<Text style={{color: 'red'}}>Balanced: </Text>
WillHaveAnHyphenWhenBreakingForNewLine
</Text>
</RNTesterBlock>
<RNTesterBlock title="Padding">
<Text style={{padding: 10}}>
This text is indented by 10px padding on all sides.

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

@ -46,7 +46,6 @@
NSHashTable<NSString *> *other = [NSHashTable new];
RCTLayoutContext layoutContext = {};
layoutContext.absolutePosition = CGPointZero;
layoutContext.affectedShadowViews = affectedShadowViews;
layoutContext.other = other;

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

@ -0,0 +1,21 @@
/*
* 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.
*/
#import <UIKit/UIKit.h>
#import <React/RCTViewComponentView.h>
NS_ASSUME_NONNULL_BEGIN
/**
* UIView class for root <InputAccessoryView> component.
*/
@interface RCTInputAccessoryComponentView : RCTViewComponentView
@end
NS_ASSUME_NONNULL_END

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

@ -0,0 +1,153 @@
/*
* 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.
*/
#import "RCTInputAccessoryComponentView.h"
#import <React/RCTBackedTextInputViewProtocol.h>
#import <React/RCTConversions.h>
#import <React/RCTSurfaceTouchHandler.h>
#import <React/UIView+React.h>
#import <react/components/inputaccessory/InputAccessoryComponentDescriptor.h>
#import <react/components/rncore/Props.h>
#import "RCTInputAccessoryContentView.h"
#import "RCTFabricComponentsPlugins.h"
using namespace facebook::react;
static UIView<RCTBackedTextInputViewProtocol> *_Nullable RCTFindTextInputWithNativeId(UIView *view, NSString *nativeId)
{
if ([view respondsToSelector:@selector(inputAccessoryViewID)] &&
[view respondsToSelector:@selector(setInputAccessoryView:)]) {
UIView<RCTBackedTextInputViewProtocol> *typed = (UIView<RCTBackedTextInputViewProtocol> *)view;
if (!nativeId || [typed.inputAccessoryViewID isEqualToString:nativeId]) {
return typed;
}
}
for (UIView *subview in view.subviews) {
UIView<RCTBackedTextInputViewProtocol> *result = RCTFindTextInputWithNativeId(subview, nativeId);
if (result) {
return result;
}
}
return nil;
}
@implementation RCTInputAccessoryComponentView {
InputAccessoryShadowNode::ConcreteState::Shared _state;
RCTInputAccessoryContentView *_contentView;
RCTSurfaceTouchHandler *_touchHandler;
UIView<RCTBackedTextInputViewProtocol> __weak *_textInput;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const InputAccessoryProps>();
_props = defaultProps;
_contentView = [RCTInputAccessoryContentView new];
_touchHandler = [RCTSurfaceTouchHandler new];
[_touchHandler attachToView:_contentView];
}
return self;
}
- (void)didMoveToWindow
{
[super didMoveToWindow];
if (self.window && !_textInput) {
if (self.nativeId) {
_textInput = RCTFindTextInputWithNativeId(self.window, self.nativeId);
_textInput.inputAccessoryView = _contentView;
} else {
_textInput = RCTFindTextInputWithNativeId(_contentView, nil);
}
if (!self.nativeId) {
[self becomeFirstResponder];
}
}
}
- (BOOL)canBecomeFirstResponder
{
return true;
}
- (UIView *)inputAccessoryView
{
return _contentView;
}
#pragma mark - RCTComponentViewProtocol
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<InputAccessoryComponentDescriptor>();
}
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
[_contentView insertSubview:childComponentView atIndex:index];
}
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index
{
[childComponentView removeFromSuperview];
}
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
auto const &oldInputAccessoryProps = *std::static_pointer_cast<InputAccessoryProps const>(_props);
auto const &newInputAccessoryProps = *std::static_pointer_cast<InputAccessoryProps const>(props);
if (newInputAccessoryProps.backgroundColor != oldInputAccessoryProps.backgroundColor) {
_contentView.backgroundColor = RCTUIColorFromSharedColor(newInputAccessoryProps.backgroundColor);
}
[super updateProps:props oldProps:oldProps];
self.hidden = true;
}
- (void)updateState:(const facebook::react::State::Shared &)state
oldState:(const facebook::react::State::Shared &)oldState
{
_state = std::static_pointer_cast<InputAccessoryShadowNode::ConcreteState const>(state);
CGSize oldScreenSize = RCTCGSizeFromSize(_state->getData().screenSize);
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
screenSize.height = std::nan("");
if (oldScreenSize.width != screenSize.width) {
auto stateData = InputAccessoryState{RCTSizeFromCGSize(screenSize)};
_state->updateState(std::move(stateData));
}
}
- (void)updateLayoutMetrics:(const facebook::react::LayoutMetrics &)layoutMetrics
oldLayoutMetrics:(const facebook::react::LayoutMetrics &)oldLayoutMetrics
{
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
[_contentView setFrame:RCTCGRectFromRect(layoutMetrics.getContentFrame())];
}
- (void)prepareForRecycle
{
[super prepareForRecycle];
_state.reset();
_textInput = nil;
}
@end
Class<RCTComponentViewProtocol> RCTInputAccessoryCls(void)
{
return RCTInputAccessoryComponentView.class;
}

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

@ -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.
*/
#import <UIKit/UIKit.h>
@interface RCTInputAccessoryContentView : UIView
@end

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

@ -0,0 +1,70 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTInputAccessoryContentView.h"
@implementation RCTInputAccessoryContentView {
UIView *_safeAreaContainer;
NSLayoutConstraint *_heightConstraint;
}
- (instancetype)init
{
if (self = [super init]) {
self.autoresizingMask = UIViewAutoresizingFlexibleHeight;
_safeAreaContainer = [UIView new];
_safeAreaContainer.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_safeAreaContainer];
_heightConstraint = [_safeAreaContainer.heightAnchor constraintEqualToConstant:0];
_heightConstraint.active = YES;
if (@available(iOS 11.0, tvOS 11.0, *)) {
[NSLayoutConstraint activateConstraints:@[
[_safeAreaContainer.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor],
[_safeAreaContainer.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor],
[_safeAreaContainer.leadingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.leadingAnchor],
[_safeAreaContainer.trailingAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.trailingAnchor]
]];
} else {
[NSLayoutConstraint activateConstraints:@[
[_safeAreaContainer.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
[_safeAreaContainer.topAnchor constraintEqualToAnchor:self.topAnchor],
[_safeAreaContainer.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
[_safeAreaContainer.trailingAnchor constraintEqualToAnchor:self.trailingAnchor]
]];
}
}
return self;
}
- (CGSize)intrinsicContentSize
{
// This is needed so the view size is based on autolayout constraints.
return CGSizeZero;
}
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index
{
[_safeAreaContainer insertSubview:view atIndex:index];
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
[_safeAreaContainer setFrame:frame];
_heightConstraint.constant = frame.size.height;
[self layoutIfNeeded];
}
- (BOOL)canBecomeFirstResponder
{
return true;
}
@end

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

@ -40,6 +40,7 @@ Class<RCTComponentViewProtocol> RCTModalHostViewCls(void) __attribute__((used));
Class<RCTComponentViewProtocol> RCTImageCls(void) __attribute__((used));
Class<RCTComponentViewProtocol> RCTParagraphCls(void) __attribute__((used));
Class<RCTComponentViewProtocol> RCTTextInputCls(void) __attribute__((used));
Class<RCTComponentViewProtocol> RCTInputAccessoryCls(void) __attribute__((used));
Class<RCTComponentViewProtocol> RCTViewCls(void) __attribute__((used));
#ifdef __cplusplus

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

@ -29,6 +29,7 @@ Class<RCTComponentViewProtocol> RCTFabricComponentsProvider(const char *name) {
{"Image", RCTImageCls},
{"Paragraph", RCTParagraphCls},
{"TextInput", RCTTextInputCls},
{"InputAccessoryView", RCTInputAccessoryCls},
{"View", RCTViewCls},
};

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

@ -58,6 +58,8 @@ using namespace facebook::react;
BOOL _didMoveToWindow;
}
#pragma mark - UIView overrides
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
@ -89,6 +91,13 @@ using namespace facebook::react;
}
}
#pragma mark - RCTViewComponentView overrides
- (NSObject *)accessibilityElement
{
return _backedTextInputView;
}
#pragma mark - RCTComponentViewProtocol
+ (ComponentDescriptorProvider)componentDescriptorProvider
@ -198,6 +207,10 @@ using namespace facebook::react;
_backedTextInputView.tintColor = RCTUIColorFromSharedColor(newTextInputProps.selectionColor);
}
if (newTextInputProps.inputAccessoryViewID != oldTextInputProps.inputAccessoryViewID) {
_backedTextInputView.inputAccessoryViewID = RCTNSStringFromString(newTextInputProps.inputAccessoryViewID);
}
[super updateProps:props oldProps:oldProps];
}
@ -230,20 +243,6 @@ using namespace facebook::react;
RCTUIEdgeInsetsFromEdgeInsets(layoutMetrics.contentInsets - layoutMetrics.borderWidth);
}
- (void)_setAttributedString:(NSAttributedString *)attributedString
{
UITextRange *selectedRange = [_backedTextInputView selectedTextRange];
_backedTextInputView.attributedText = attributedString;
if (_lastStringStateWasUpdatedWith.length == attributedString.length) {
// Calling `[_backedTextInputView setAttributedText]` moves caret
// to the end of text input field. This cancels any selection as well
// as position in the text input field. In case the length of string
// doesn't change, selection and caret position is maintained.
[_backedTextInputView setSelectedTextRange:selectedRange notifyDelegate:NO];
}
_lastStringStateWasUpdatedWith = attributedString;
}
- (void)prepareForRecycle
{
[super prepareForRecycle];
@ -256,19 +255,6 @@ using namespace facebook::react;
_didMoveToWindow = NO;
}
#pragma mark - RCTComponentViewProtocol
- (void)_setMultiline:(BOOL)multiline
{
[_backedTextInputView removeFromSuperview];
UIView<RCTBackedTextInputViewProtocol> *backedTextInputView =
multiline ? [[RCTUITextView alloc] init] : [[RCTUITextField alloc] init];
backedTextInputView.frame = _backedTextInputView.frame;
RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView);
_backedTextInputView = backedTextInputView;
[self addSubview:_backedTextInputView];
}
#pragma mark - RCTBackedTextInputDelegate
- (BOOL)textInputShouldBeginEditing
@ -393,41 +379,6 @@ using namespace facebook::react;
}
}
#pragma mark - Other
- (TextInputMetrics)_textInputMetrics
{
TextInputMetrics metrics;
metrics.text = RCTStringFromNSString(_backedTextInputView.attributedText.string);
metrics.selectionRange = [self _selectionRange];
metrics.eventCount = _mostRecentEventCount;
return metrics;
}
- (void)_updateState
{
if (!_state) {
return;
}
NSAttributedString *attributedString = _backedTextInputView.attributedText;
auto data = _state->getData();
_lastStringStateWasUpdatedWith = attributedString;
data.attributedStringBox = RCTAttributedStringBoxFromNSAttributedString(attributedString);
_mostRecentEventCount += _comingFromJS ? 0 : 1;
data.mostRecentEventCount = _mostRecentEventCount;
_state->updateState(std::move(data));
}
- (AttributedString::Range)_selectionRange
{
UITextRange *selectedTextRange = _backedTextInputView.selectedTextRange;
NSInteger start = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:selectedTextRange.start];
NSInteger end = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:selectedTextRange.end];
return AttributedString::Range{(int)start, (int)(end - start)};
}
#pragma mark - Native Commands
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
@ -475,6 +426,66 @@ using namespace facebook::react;
_comingFromJS = NO;
}
#pragma mark - Other
- (TextInputMetrics)_textInputMetrics
{
TextInputMetrics metrics;
metrics.text = RCTStringFromNSString(_backedTextInputView.attributedText.string);
metrics.selectionRange = [self _selectionRange];
metrics.eventCount = _mostRecentEventCount;
return metrics;
}
- (void)_updateState
{
if (!_state) {
return;
}
NSAttributedString *attributedString = _backedTextInputView.attributedText;
auto data = _state->getData();
_lastStringStateWasUpdatedWith = attributedString;
data.attributedStringBox = RCTAttributedStringBoxFromNSAttributedString(attributedString);
_mostRecentEventCount += _comingFromJS ? 0 : 1;
data.mostRecentEventCount = _mostRecentEventCount;
_state->updateState(std::move(data));
}
- (AttributedString::Range)_selectionRange
{
UITextRange *selectedTextRange = _backedTextInputView.selectedTextRange;
NSInteger start = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:selectedTextRange.start];
NSInteger end = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:selectedTextRange.end];
return AttributedString::Range{(int)start, (int)(end - start)};
}
- (void)_setAttributedString:(NSAttributedString *)attributedString
{
UITextRange *selectedRange = [_backedTextInputView selectedTextRange];
_backedTextInputView.attributedText = attributedString;
if (_lastStringStateWasUpdatedWith.length == attributedString.length) {
// Calling `[_backedTextInputView setAttributedText]` moves caret
// to the end of text input field. This cancels any selection as well
// as position in the text input field. In case the length of string
// doesn't change, selection and caret position is maintained.
[_backedTextInputView setSelectedTextRange:selectedRange notifyDelegate:NO];
}
_lastStringStateWasUpdatedWith = attributedString;
}
- (void)_setMultiline:(BOOL)multiline
{
[_backedTextInputView removeFromSuperview];
UIView<RCTBackedTextInputViewProtocol> *backedTextInputView =
multiline ? [[RCTUITextView alloc] init] : [[RCTUITextField alloc] init];
backedTextInputView.frame = _backedTextInputView.frame;
RCTCopyBackedTextInput(_backedTextInputView, backedTextInputView);
_backedTextInputView = backedTextInputView;
[self addSubview:_backedTextInputView];
}
@end
Class<RCTComponentViewProtocol> RCTTextInputCls(void)

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

@ -53,18 +53,6 @@ using namespace facebook::react;
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Consider whether using `updateLayoutMetrics:oldLayoutMetrics`
// isn't more appropriate for your use case. `layoutSubviews` is called
// by UIKit while `updateLayoutMetrics:oldLayoutMetrics` is called
// by React Native Renderer within `CATransaction`.
// If you are calling `setFrame:` or other methods that cause
// `layoutSubviews` to be triggered, `_contentView`'s and `_borderLayout`'s
// frames might get out of sync with `self.bounds`.
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if (UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero)) {

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

@ -18,60 +18,6 @@
using namespace facebook::react;
#define LEGACY_UIMANAGER_INTEGRATION_ENABLED 1
#ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED
#import <React/RCTBridge+Private.h>
#import <React/RCTUIManager.h>
/**
* Warning: This is a total hack and temporary solution.
* Unless we have a pure Fabric-based implementation of UIManager commands
* delivery pipeline, we have to leverage existing infra. This code tricks
* legacy UIManager by registering all Fabric-managed views in it,
* hence existing command-delivery infra can reach "foreign" views using
* the old pipeline.
*/
@interface RCTUIManager ()
- (NSMutableDictionary<NSNumber *, UIView *> *)viewRegistry;
@end
@interface RCTUIManager (Hack)
+ (void)registerView:(UIView *)view;
+ (void)unregisterView:(UIView *)view;
@end
@implementation RCTUIManager (Hack)
+ (void)registerView:(UIView *)view
{
if (!view) {
return;
}
RCTUIManager *uiManager = [[RCTBridge currentBridge] uiManager];
view.reactTag = @(view.tag);
[uiManager.viewRegistry setObject:view forKey:@(view.tag)];
}
+ (void)unregisterView:(UIView *)view
{
if (!view) {
return;
}
RCTUIManager *uiManager = [[RCTBridge currentBridge] uiManager];
view.reactTag = nil;
[uiManager.viewRegistry removeObjectForKey:@(view.tag)];
}
@end
#endif
const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
@implementation RCTComponentViewRegistry {
@ -133,10 +79,6 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
_registry.insert({tag, componentViewDescriptor});
#ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED
[RCTUIManager registerView:componentViewDescriptor.view];
#endif
return componentViewDescriptor;
}
@ -149,10 +91,6 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
RCTAssert(
_registry.find(tag) != _registry.end(), @"RCTComponentViewRegistry: Attempt to enqueue unregistered component.");
#ifdef LEGACY_UIMANAGER_INTEGRATION_ENABLED
[RCTUIManager unregisterView:componentViewDescriptor.view];
#endif
_registry.erase(tag);
componentViewDescriptor.view.tag = 0;
[self _enqueueComponentViewWithComponentHandle:componentHandle componentViewDescriptor:componentViewDescriptor];

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

@ -74,6 +74,11 @@ NS_ASSUME_NONNULL_BEGIN
- (void)removeObserver:(id<RCTSurfacePresenterObserver>)observer;
/*
* Please do not use this, this will be deleted soon.
*/
- (nullable UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag;
@end
NS_ASSUME_NONNULL_END

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

@ -191,6 +191,13 @@ static inline LayoutContext RCTGetLayoutContext()
surfaceId:surface.rootTag];
}
- (UIView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag
{
UIView<RCTComponentViewProtocol> *componentView =
[_mountingManager.componentViewRegistry findComponentViewWithTag:tag];
return componentView;
}
- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props
{
RCTScheduler *scheduler = [self _scheduler];

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

@ -8,6 +8,7 @@
#import <objc/runtime.h>
#import <React/RCTBridge.h>
#import <React/RCTUIKit.h> // TODO(macOS GH#774)
NS_ASSUME_NONNULL_BEGIN
@ -26,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol RCTSurfacePresenterStub <NSObject>
- (nullable RCTPlatformView *)findComponentViewWithTag_DO_NOT_USE_DEPRECATED:(NSInteger)tag; // TODO(macOS GH#774)
- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
- (void)addObserver:(id<RCTSurfacePresenterObserver>)observer;
- (void)removeObserver:(id<RCTSurfacePresenterObserver>)observer;

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

@ -8,6 +8,7 @@
#import "RCTUIManager.h"
#import <AVFoundation/AVFoundation.h>
#import <React/RCTSurfacePresenterStub.h>
#import <yoga/Yoga.h> // TODO(macOS GH#774)
@ -369,7 +370,11 @@ static NSDictionary *deviceOrientationEventBody(UIDeviceOrientation orientation)
- (RCTPlatformView *)viewForReactTag:(NSNumber *)reactTag // TODO(macOS GH#774)
{
RCTAssertMainQueue();
return _viewRegistry[reactTag];
RCTPlatformView *view = [_bridge.surfacePresenter findComponentViewWithTag_DO_NOT_USE_DEPRECATED:reactTag.integerValue]; // TODO(macOS GH#774)
if (!view) {
view = _viewRegistry[reactTag];
}
return view;
}
- (RCTShadowView *)shadowViewForReactTag:(NSNumber *)reactTag
@ -1475,7 +1480,8 @@ RCT_EXPORT_METHOD(setJSResponder
{
[self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTPlatformView *> *viewRegistry) { // TODO(macOS GH#774)
_jsResponder = viewRegistry[reactTag];
if (!_jsResponder) {
// Fabric view's are not stored in viewRegistry. We avoid logging a warning in that case.
if (!_jsResponder && !RCTUIManagerTypeForTagIsFabric(reactTag)) {
RCTLogWarn(@"Invalid view set to be the JS responder - tag %@", reactTag);
}
}];

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

@ -66,6 +66,9 @@ public abstract class NativeAnimatedModuleSpec extends ReactContextBaseJavaModul
public abstract void startAnimatingNode(double animationId, double nodeTag, ReadableMap config,
Callback endCallback);
@ReactMethod
public abstract void getValue(double tag, Callback saveValueCallback);
@ReactMethod
public abstract void stopListeningToAnimatedNodeValue(double tag);

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

@ -186,6 +186,10 @@ namespace facebook {
return static_cast<JavaTurboModule&>(turboModule).invokeJavaMethod(rt, VoidKind, "createAnimatedNode", "(DLcom/facebook/react/bridge/ReadableMap;)V", args, count);
}
static facebook::jsi::Value __hostFunction_NativeAnimatedModuleSpecJSI_getValue(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<JavaTurboModule&>(turboModule).invokeJavaMethod(rt, VoidKind, "getValue", "(DLcom/facebook/react/bridge/Callback;)V", args, count);
}
static facebook::jsi::Value __hostFunction_NativeAnimatedModuleSpecJSI_startListeningToAnimatedNodeValue(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<JavaTurboModule&>(turboModule).invokeJavaMethod(rt, VoidKind, "startListeningToAnimatedNodeValue", "(D)V", args, count);
}
@ -265,6 +269,9 @@ namespace facebook {
methodMap_["createAnimatedNode"] = MethodMetadata {2, __hostFunction_NativeAnimatedModuleSpecJSI_createAnimatedNode};
methodMap_["getValue"] = MethodMetadata {2, __hostFunction_NativeAnimatedModuleSpecJSI_getValue};
methodMap_["startListeningToAnimatedNodeValue"] = MethodMetadata {1, __hostFunction_NativeAnimatedModuleSpecJSI_startListeningToAnimatedNodeValue};

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

@ -774,4 +774,16 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
public void removeListeners(double count) {
// iOS only
}
@Override
public void getValue(final double animatedValueNodeTagDouble, final Callback callback) {
final int animatedValueNodeTag = (int) animatedValueNodeTagDouble;
mOperations.add(
new UIThreadOperation() {
@Override
public void execute(NativeAnimatedNodesManager animatedNodesManager) {
animatedNodesManager.getValue(animatedValueNodeTag, callback);
}
});
}
}

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

@ -352,6 +352,15 @@ import java.util.Queue;
propsAnimatedNode.disconnectFromView(viewTag);
}
public void getValue(int tag, Callback callback) {
AnimatedNode node = mAnimatedNodes.get(tag);
if (node == null || !(node instanceof ValueAnimatedNode)) {
throw new JSApplicationIllegalArgumentException(
"Animated node with tag " + tag + " does not exists or is not a 'value' node");
}
callback.invoke(((ValueAnimatedNode) node).getValue());
}
public void restoreDefaultValues(int animatedNodeTag) {
AnimatedNode node = mAnimatedNodes.get(animatedNodeTag);
// Restoring default values needs to happen before UIManager operations so it is

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

@ -340,16 +340,6 @@ public class CatalystInstanceImpl implements CatalystInstance {
FLog.d(ReactConstants.TAG, "CatalystInstanceImpl.destroy() start");
UiThreadUtil.assertOnUiThread();
if (ReactFeatureFlags.useCatalystTeardownV2) {
destroyV2();
} else {
destroyV1();
}
}
@ThreadConfined(UI)
public void destroyV1() {
FLog.d(ReactConstants.TAG, "CatalystInstanceImpl.destroyV1() start");
UiThreadUtil.assertOnUiThread();
if (mDestroyed) {
@ -427,101 +417,6 @@ public class CatalystInstanceImpl implements CatalystInstance {
Systrace.unregisterListener(mTraceListener);
}
/**
* Destroys this catalyst instance, waiting for any other threads in ReactQueueConfiguration
* (besides the UI thread) to finish running. Must be called from the UI thread so that we can
* fully shut down other threads.
*/
@ThreadConfined(UI)
public void destroyV2() {
FLog.d(ReactConstants.TAG, "CatalystInstanceImpl.destroyV2() start");
UiThreadUtil.assertOnUiThread();
if (mDestroyed) {
return;
}
// TODO: tell all APIs to shut down
ReactMarker.logMarker(ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_START);
mDestroyed = true;
mNativeModulesThreadDestructionComplete = false;
mJSThreadDestructionComplete = false;
mNativeModulesQueueThread.runOnQueue(
new Runnable() {
@Override
public void run() {
FLog.d("CatalystInstanceImpl", ".destroy on native modules thread");
mNativeModuleRegistry.notifyJSInstanceDestroy();
// Notifies all JSI modules that they are being destroyed, including the FabricUIManager
// and Fabric Scheduler
mJSIModuleRegistry.notifyJSInstanceDestroy();
boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0);
if (!mBridgeIdleListeners.isEmpty()) {
for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) {
if (!wasIdle) {
listener.onTransitionToBridgeIdle();
}
listener.onBridgeDestroyed();
}
}
mNativeModulesThreadDestructionComplete = true;
FLog.d("CatalystInstanceImpl", ".destroy on native modules thread finished");
}
});
getReactQueueConfiguration()
.getJSQueueThread()
.runOnQueue(
new Runnable() {
@Override
public void run() {
FLog.d("CatalystInstanceImpl", ".destroy on JS thread");
// We need to destroy the TurboModuleManager on the JS Thread
if (mTurboModuleManagerJSIModule != null) {
mTurboModuleManagerJSIModule.onCatalystInstanceDestroy();
}
mJSThreadDestructionComplete = true;
FLog.d("CatalystInstanceImpl", ".destroy on JS thread finished");
}
});
// Wait until destruction is complete
long waitStartTime = System.currentTimeMillis();
while (!mNativeModulesThreadDestructionComplete || !mJSThreadDestructionComplete) {
// Never wait here, blocking the UI thread, for more than 100ms
if ((System.currentTimeMillis() - waitStartTime) > 100) {
FLog.w(
ReactConstants.TAG,
"CatalystInstanceImpl.destroy() timed out waiting for Native Modules and JS thread teardown");
break;
}
}
// Kill non-UI threads from neutral third party
// potentially expensive, so don't run on UI thread
// contextHolder is used as a lock to guard against
// other users of the JS VM having the VM destroyed
// underneath them, so notify them before we reset
// Native
mJavaScriptContextHolder.clear();
// Imperatively destruct the C++ CatalystInstance rather than
// wait for the JVM's GC to free it.
mHybridData.resetNative();
getReactQueueConfiguration().destroy();
FLog.d(ReactConstants.TAG, "CatalystInstanceImpl.destroy() end");
ReactMarker.logMarker(ReactMarkerConstants.DESTROY_CATALYST_INSTANCE_END);
// This is a noop if the listener was not yet registered.
Systrace.unregisterListener(mTraceListener);
}
@Override
public boolean isDestroyed() {
return mDestroyed;

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

@ -296,9 +296,6 @@ public class ReactContext extends ContextWrapper {
mDestroyed = true;
if (mCatalystInstance != null) {
mCatalystInstance.destroy();
if (ReactFeatureFlags.nullifyCatalystInstanceOnDestroy) {
mCatalystInstance = null;
}
}
}

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

@ -41,28 +41,7 @@ public class ReactFeatureFlags {
* inside view manager will be called instead.
*/
public static boolean useViewManagerDelegatesForCommands = false;
/**
* Should this application use Catalyst Teardown V2? This is an experiment to use a V2 of the
* CatalystInstanceImpl `destroy` method.
*/
public static boolean useCatalystTeardownV2 = false;
/**
* When the ReactContext is destroyed, should the CatalystInstance immediately be nullified? This
* is the safest thing to do since the CatalystInstance shouldn't be used, and should be
* garbage-collected after it's destroyed, but this is a breaking change in that many native
* modules assume that a ReactContext will always have a CatalystInstance. This will be deleted
* and the CatalystInstance will always be destroyed in some future release.
*/
public static boolean nullifyCatalystInstanceOnDestroy = false;
/**
* Temporary flag. See UIImplementation: if this flag is enabled, ViewCommands will be queued and
* executed before any other types of UI operations.
*/
public static boolean allowEarlyViewCommandExecution = false;
/**
* This react flag enables a custom algorithm for the getChildVisibleRect() method in the classes
* ReactViewGroup, ReactHorizontalScrollView and ReactScrollView.
@ -87,9 +66,6 @@ public class ReactFeatureFlags {
/** Feature flag to configure initialization of Fabric surfaces. */
public static boolean enableFabricStartSurfaceWithLayoutMetrics = true;
/** Feature flag to have FabricUIManager teardown stop all active surfaces. */
public static boolean enableFabricStopAllSurfacesOnTeardown = false;
/** Feature flag to use stopSurface when ReactRootView is unmounted. */
public static boolean enableStopSurfaceOnRootViewUnmount = false;
}

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

@ -21,7 +21,6 @@ import com.facebook.react.fabric.mounting.LayoutMetricsConversions;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.mountitems.BatchMountItem;
import com.facebook.react.fabric.mounting.mountitems.CreateMountItem;
import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem;
import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem;
import com.facebook.react.fabric.mounting.mountitems.DispatchIntCommandMountItem;
import com.facebook.react.fabric.mounting.mountitems.DispatchStringCommandMountItem;
@ -29,7 +28,6 @@ import com.facebook.react.fabric.mounting.mountitems.InsertMountItem;
import com.facebook.react.fabric.mounting.mountitems.MountItem;
import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem;
import com.facebook.react.fabric.mounting.mountitems.RemoveDeleteMultiMountItem;
import com.facebook.react.fabric.mounting.mountitems.RemoveMountItem;
import com.facebook.react.fabric.mounting.mountitems.SendAccessibilityEvent;
import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem;
import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem;
@ -112,7 +110,6 @@ public class FabricJSIModuleProvider implements JSIModuleProvider<UIManager> {
FabricEventEmitter.class.getClass();
BatchMountItem.class.getClass();
CreateMountItem.class.getClass();
DeleteMountItem.class.getClass();
DispatchCommandMountItem.class.getClass();
DispatchIntCommandMountItem.class.getClass();
DispatchStringCommandMountItem.class.getClass();
@ -120,7 +117,6 @@ public class FabricJSIModuleProvider implements JSIModuleProvider<UIManager> {
MountItem.class.getClass();
PreAllocateViewMountItem.class.getClass();
RemoveDeleteMultiMountItem.class.getClass();
RemoveMountItem.class.getClass();
SendAccessibilityEvent.class.getClass();
UpdateEventEmitterMountItem.class.getClass();
UpdateLayoutMountItem.class.getClass();

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

@ -56,7 +56,6 @@ import com.facebook.react.fabric.events.FabricEventEmitter;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.mountitems.BatchMountItem;
import com.facebook.react.fabric.mounting.mountitems.CreateMountItem;
import com.facebook.react.fabric.mounting.mountitems.DeleteMountItem;
import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem;
import com.facebook.react.fabric.mounting.mountitems.DispatchIntCommandMountItem;
import com.facebook.react.fabric.mounting.mountitems.DispatchStringCommandMountItem;
@ -64,7 +63,6 @@ import com.facebook.react.fabric.mounting.mountitems.InsertMountItem;
import com.facebook.react.fabric.mounting.mountitems.MountItem;
import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem;
import com.facebook.react.fabric.mounting.mountitems.RemoveDeleteMultiMountItem;
import com.facebook.react.fabric.mounting.mountitems.RemoveMountItem;
import com.facebook.react.fabric.mounting.mountitems.SendAccessibilityEvent;
import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem;
import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem;
@ -255,8 +253,8 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
@ThreadConfined(ANY)
@Override
public void stopSurface(int surfaceID) {
mBinding.stopSurface(surfaceID);
mReactContextForRootTag.remove(surfaceID);
mBinding.stopSurface(surfaceID);
}
@Override
@ -299,15 +297,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
// memory immediately.
mDispatchUIFrameCallback.stop();
// Stop all attached surfaces
if (ReactFeatureFlags.enableFabricStopAllSurfacesOnTeardown) {
FLog.e(TAG, "stop all attached surfaces");
for (int surfaceId : mReactContextForRootTag.keySet()) {
FLog.e(TAG, "stop attached surface: " + surfaceId);
stopSurface(surfaceId);
}
}
mBinding.unregister();
mBinding = null;
@ -367,14 +356,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
isLayoutable);
}
@DoNotStrip
@SuppressWarnings("unused")
@AnyThread
@ThreadConfined(ANY)
private MountItem removeMountItem(int reactTag, int parentReactTag, int index) {
return new RemoveMountItem(reactTag, parentReactTag, index);
}
@DoNotStrip
@SuppressWarnings("unused")
@AnyThread
@ -383,14 +364,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
return new InsertMountItem(reactTag, parentReactTag, index);
}
@DoNotStrip
@SuppressWarnings("unused")
@AnyThread
@ThreadConfined(ANY)
private MountItem deleteMountItem(int reactTag) {
return new DeleteMountItem(reactTag);
}
@DoNotStrip
@SuppressWarnings("unused")
@AnyThread
@ -701,10 +674,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
@UiThread
@ThreadConfined(UI)
private List<DispatchCommandMountItem> getAndResetViewCommandMountItems() {
if (!ReactFeatureFlags.allowEarlyViewCommandExecution) {
return null;
}
synchronized (mViewCommandMountItemsLock) {
List<DispatchCommandMountItem> result = mViewCommandMountItems;
if (result.isEmpty()) {
@ -884,33 +853,12 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
BatchMountItem batchMountItem = (BatchMountItem) mountItem;
if (!surfaceActiveForExecution(
batchMountItem.getRootTag(), "dispatchMountItems BatchMountItem")) {
batchMountItem.executeDeletes(mMountingManager);
continue;
}
}
// TODO: if early ViewCommand dispatch ships 100% as a feature, this can be removed.
// This try/catch catches Retryable errors that can only be thrown by ViewCommands, which
// won't be executed here in Early Dispatch mode.
try {
mountItem.execute(mMountingManager);
} catch (RetryableMountingLayerException e) {
// It's very common for commands to be executed on views that no longer exist - for
// example, a blur event on TextInput being fired because of a navigation event away
// from the current screen. If the exception is marked as Retryable, we log a soft
// exception but never crash in debug.
// It's not clear that logging this is even useful, because these events are very
// common, mundane, and there's not much we can do about them currently.
if (mountItem instanceof DispatchCommandMountItem) {
ReactSoftException.logSoftException(
TAG,
new ReactNoCrashSoftException(
"Caught exception executing retryable mounting layer instruction: "
+ mountItem.toString(),
e));
} else {
throw e;
}
}
mountItem.execute(mMountingManager);
}
mBatchedExecutionTime += SystemClock.uptimeMillis() - batchedExecutionStartTime;
}
@ -1045,14 +993,8 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
@AnyThread
@ThreadConfined(ANY)
private void dispatchCommandMountItem(DispatchCommandMountItem command) {
if (ReactFeatureFlags.allowEarlyViewCommandExecution) {
synchronized (mViewCommandMountItemsLock) {
mViewCommandMountItems.add(command);
}
} else {
synchronized (mMountItemsLock) {
mMountItems.add(command);
}
synchronized (mViewCommandMountItemsLock) {
mViewCommandMountItems.add(command);
}
}

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

@ -280,8 +280,6 @@ void Binding::installFabricUIManager(
// Keep reference to config object and cache some feature flags here
reactNativeConfig_ = config;
shouldCollateRemovesAndDeletes_ = reactNativeConfig_->getBool(
"react_fabric:enable_removedelete_collation_android");
collapseDeleteCreateMountingInstructions_ = reactNativeConfig_->getBool(
"react_fabric:enabled_collapse_delete_create_mounting_instructions");
@ -491,31 +489,6 @@ local_ref<JMountItem::javaobject> createUpdateStateMountItem(
(javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr));
}
local_ref<JMountItem::javaobject> createRemoveMountItem(
const jni::global_ref<jobject> &javaUIManager,
const ShadowViewMutation &mutation) {
static auto removeInstruction =
jni::findClassStatic(Binding::UIManagerJavaDescriptor)
->getMethod<alias_ref<JMountItem>(jint, jint, jint)>(
"removeMountItem");
return removeInstruction(
javaUIManager,
mutation.oldChildShadowView.tag,
mutation.parentShadowView.tag,
mutation.index);
}
local_ref<JMountItem::javaobject> createDeleteMountItem(
const jni::global_ref<jobject> &javaUIManager,
const ShadowViewMutation &mutation) {
static auto deleteInstruction =
jni::findClassStatic(Binding::UIManagerJavaDescriptor)
->getMethod<alias_ref<JMountItem>(jint)>("deleteMountItem");
return deleteInstruction(javaUIManager, mutation.oldChildShadowView.tag);
}
local_ref<JMountItem::javaobject> createRemoveAndDeleteMultiMountItem(
const jni::global_ref<jobject> &javaUIManager,
const std::vector<RemoveDeleteMetadata> &metadata) {
@ -685,8 +658,7 @@ void Binding::schedulerDidFinishTransaction(
oldChildShadowView.layoutMetrics == EmptyLayoutMetrics;
// Handle accumulated removals/deletions
if (shouldCollateRemovesAndDeletes_ &&
mutation.type != ShadowViewMutation::Remove &&
if (mutation.type != ShadowViewMutation::Remove &&
mutation.type != ShadowViewMutation::Delete) {
if (toRemove.size() > 0) {
mountItems[position++] =
@ -708,39 +680,29 @@ void Binding::schedulerDidFinishTransaction(
}
case ShadowViewMutation::Remove: {
if (!isVirtual) {
if (shouldCollateRemovesAndDeletes_) {
toRemove.push_back(
RemoveDeleteMetadata{mutation.oldChildShadowView.tag,
mutation.parentShadowView.tag,
mutation.index,
true,
false});
} else {
mountItems[position++] =
createRemoveMountItem(localJavaUIManager, mutation);
}
toRemove.push_back(
RemoveDeleteMetadata{mutation.oldChildShadowView.tag,
mutation.parentShadowView.tag,
mutation.index,
true,
false});
}
break;
}
case ShadowViewMutation::Delete: {
if (shouldCollateRemovesAndDeletes_) {
// It is impossible to delete without removing node first
const auto &it = std::find_if(
std::begin(toRemove),
std::end(toRemove),
[&mutation](const auto &x) {
return x.tag == mutation.oldChildShadowView.tag;
});
// It is impossible to delete without removing node first
const auto &it = std::find_if(
std::begin(toRemove),
std::end(toRemove),
[&mutation](const auto &x) {
return x.tag == mutation.oldChildShadowView.tag;
});
if (it != std::end(toRemove)) {
it->shouldDelete = true;
} else {
toRemove.push_back(RemoveDeleteMetadata{
mutation.oldChildShadowView.tag, -1, -1, false, true});
}
if (it != std::end(toRemove)) {
it->shouldDelete = true;
} else {
mountItems[position++] =
createDeleteMountItem(localJavaUIManager, mutation);
toRemove.push_back(RemoveDeleteMetadata{
mutation.oldChildShadowView.tag, -1, -1, false, true});
}
deletedViewTags.insert(mutation.oldChildShadowView.tag);
@ -840,7 +802,7 @@ void Binding::schedulerDidFinishTransaction(
}
// Handle remaining removals and deletions
if (shouldCollateRemovesAndDeletes_ && toRemove.size() > 0) {
if (toRemove.size() > 0) {
mountItems[position++] =
createRemoveAndDeleteMultiMountItem(localJavaUIManager, toRemove);
toRemove.clear();

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

@ -125,7 +125,6 @@ class Binding : public jni::HybridClass<Binding>,
float pointScaleFactor_ = 1;
std::shared_ptr<const ReactNativeConfig> reactNativeConfig_{nullptr};
bool shouldCollateRemovesAndDeletes_{false};
bool collapseDeleteCreateMountingInstructions_{false};
bool disablePreallocateViews_{false};
bool disableVirtualNodePreallocation_{false};

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

@ -281,19 +281,17 @@ public class MountingManager {
ViewGroupManager<ViewGroup> viewGroupManager = getViewGroupManager(viewState);
// Verify that the view we're about to remove has the same tag we expect
if (tag != -1) {
View view = viewGroupManager.getChildAt(parentView, index);
if (view != null && view.getId() != tag) {
throw new IllegalStateException(
"Tried to delete view ["
+ tag
+ "] of parent ["
+ parentTag
+ "] at index "
+ index
+ ", but got view tag "
+ view.getId());
}
View view = viewGroupManager.getChildAt(parentView, index);
if (view != null && view.getId() != tag) {
throw new IllegalStateException(
"Tried to delete view ["
+ tag
+ "] of parent ["
+ parentTag
+ "] at index "
+ index
+ ", but got view tag "
+ view.getId());
}
try {
@ -457,15 +455,6 @@ public class MountingManager {
View view = viewState.mView;
if (view != null) {
ViewParent parentView = view.getParent();
if (parentView != null) {
ReactSoftException.logSoftException(
TAG,
new IllegalStateException(
"Warning: Deleting view that is still attached to parent: [" + reactTag + "]"));
}
dropView(view);
} else {
mTagToViewState.remove(reactTag);

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

@ -45,21 +45,18 @@ public class BatchMountItem implements MountItem {
mCommitNumber = commitNumber;
}
@Override
public void execute(@NonNull MountingManager mountingManager) {
private void beginMarkers(String reason) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricUIManager::mountViews - " + mSize + " items");
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"FabricUIManager::" + reason + " - " + mSize + " items");
if (mCommitNumber > 0) {
ReactMarker.logFabricMarker(
ReactMarkerConstants.FABRIC_BATCH_EXECUTION_START, null, mCommitNumber);
}
}
for (int mountItemIndex = 0; mountItemIndex < mSize; mountItemIndex++) {
MountItem mountItem = mMountItems[mountItemIndex];
mountItem.execute(mountingManager);
}
private void endMarkers() {
if (mCommitNumber > 0) {
ReactMarker.logFabricMarker(
ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END, null, mCommitNumber);
@ -68,6 +65,31 @@ public class BatchMountItem implements MountItem {
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}
@Override
public void execute(@NonNull MountingManager mountingManager) {
beginMarkers("mountViews");
for (int mountItemIndex = 0; mountItemIndex < mSize; mountItemIndex++) {
MountItem mountItem = mMountItems[mountItemIndex];
mountItem.execute(mountingManager);
}
endMarkers();
}
public void executeDeletes(@NonNull MountingManager mountingManager) {
beginMarkers("deleteViews");
for (int mountItemIndex = 0; mountItemIndex < mSize; mountItemIndex++) {
MountItem mountItem = mMountItems[mountItemIndex];
if (mountItem instanceof RemoveDeleteMultiMountItem) {
((RemoveDeleteMultiMountItem) mountItem).executeDeletes(mountingManager, true);
}
}
endMarkers();
}
public int getRootTag() {
return mRootTag;
}

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

@ -1,30 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.fabric.mounting.mountitems;
import androidx.annotation.NonNull;
import com.facebook.react.fabric.mounting.MountingManager;
public class DeleteMountItem implements MountItem {
private int mReactTag;
public DeleteMountItem(int reactTag) {
mReactTag = reactTag;
}
@Override
public void execute(@NonNull MountingManager mountingManager) {
mountingManager.deleteView(mReactTag);
}
@Override
public String toString() {
return "DeleteMountItem [" + mReactTag + "]";
}
}

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

@ -56,11 +56,30 @@ public class RemoveDeleteMultiMountItem implements MountItem {
}
// After removing all views, delete all views marked for deletion.
executeDeletes(mountingManager, false);
}
/**
* Execute only deletion operations. When being executed as part of shutdown/stopping surface,
* deletion failures can be ignored. For example: if there is a batch of MountItems being executed
* as part of stopSurface, a "Create" that is not executed may have a matching "Delete". The
* Delete will fail but we can safely ignore it in those cases.
*
* @param mountingManager
* @param ignoreFailures
*/
public void executeDeletes(@NonNull MountingManager mountingManager, boolean ignoreFailures) {
for (int i = 0; i < mMetadata.length; i += 4) {
int flags = mMetadata[i + FLAGS_INDEX];
if ((flags & DELETE_FLAG) != 0) {
int tag = mMetadata[i + TAG_INDEX];
mountingManager.deleteView(tag);
try {
mountingManager.deleteView(tag);
} catch (IllegalStateException e) {
if (!ignoreFailures) {
throw e;
}
}
}
}
}

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

@ -1,47 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.fabric.mounting.mountitems;
import androidx.annotation.NonNull;
import com.facebook.react.fabric.mounting.MountingManager;
public class RemoveMountItem implements MountItem {
private int mReactTag;
private int mParentReactTag;
private int mIndex;
public RemoveMountItem(int reactTag, int parentReactTag, int index) {
mReactTag = reactTag;
mParentReactTag = parentReactTag;
mIndex = index;
}
@Override
public void execute(@NonNull MountingManager mountingManager) {
mountingManager.removeViewAt(-1, mParentReactTag, mIndex);
}
public int getParentReactTag() {
return mParentReactTag;
}
public int getIndex() {
return mIndex;
}
@Override
public String toString() {
return "RemoveMountItem ["
+ mReactTag
+ "] - parentTag: "
+ mParentReactTag
+ " - index: "
+ mIndex;
}
}

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

@ -25,7 +25,6 @@ import com.facebook.react.bridge.RetryableMountingLayerException;
import com.facebook.react.bridge.SoftAssertions;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.modules.core.ReactChoreographer;
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
import com.facebook.systrace.Systrace;
@ -596,7 +595,6 @@ public class UIViewOperationQueue {
private final DispatchUIFrameCallback mDispatchUIFrameCallback;
private final ReactApplicationContext mReactApplicationContext;
private final boolean mAllowViewCommandsQueue;
private ArrayList<DispatchCommandViewOperation> mViewCommandOperations = new ArrayList<>();
// Only called from the UIManager queue?
@ -637,7 +635,6 @@ public class UIViewOperationQueue {
? DEFAULT_MIN_TIME_LEFT_IN_FRAME_FOR_NONBATCHED_OPERATION_MS
: minTimeLeftInFrameForNonBatchedOperationMs);
mReactApplicationContext = reactContext;
mAllowViewCommandsQueue = ReactFeatureFlags.allowEarlyViewCommandExecution;
}
/*package*/ NativeViewHierarchyManager getNativeViewHierarchyManager() {
@ -709,22 +706,14 @@ public class UIViewOperationQueue {
int reactTag, int commandId, @Nullable ReadableArray commandArgs) {
final DispatchCommandOperation command =
new DispatchCommandOperation(reactTag, commandId, commandArgs);
if (mAllowViewCommandsQueue) {
mViewCommandOperations.add(command);
} else {
mOperations.add(command);
}
mViewCommandOperations.add(command);
}
public void enqueueDispatchCommand(
int reactTag, String commandId, @Nullable ReadableArray commandArgs) {
final DispatchStringCommandOperation command =
new DispatchStringCommandOperation(reactTag, commandId, commandArgs);
if (mAllowViewCommandsQueue) {
mViewCommandOperations.add(command);
} else {
mOperations.add(command);
}
mViewCommandOperations.add(command);
}
public void enqueueUpdateExtraData(int reactTag, Object extraData) {

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

@ -17,6 +17,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStructure;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
@ -347,24 +348,26 @@ public class ReactModalHostView extends ViewGroup implements LifecycleEventListe
Assertions.assertNotNull(mDialog, "mDialog must exist when we call updateProperties");
Activity currentActivity = getCurrentActivity();
if (currentActivity != null) {
int activityWindowFlags = currentActivity.getWindow().getAttributes().flags;
if ((activityWindowFlags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
Window window = mDialog.getWindow();
if (currentActivity == null || currentActivity.isFinishing() || !window.isActive()) {
// If the activity has disappeared, then we shouldn't update the window associated to the
// Dialog.
return;
}
int activityWindowFlags = currentActivity.getWindow().getAttributes().flags;
if ((activityWindowFlags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0) {
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
if (mTransparent) {
mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
} else {
mDialog.getWindow().setDimAmount(0.5f);
mDialog
.getWindow()
.setFlags(
WindowManager.LayoutParams.FLAG_DIM_BEHIND,
WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setDimAmount(0.5f);
window.setFlags(
WindowManager.LayoutParams.FLAG_DIM_BEHIND, WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
}

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

@ -307,6 +307,8 @@ public class ReactHorizontalScrollViewManager extends ViewGroupManager<ReactHori
double x = value.hasKey("x") ? value.getDouble("x") : 0;
double y = value.hasKey("y") ? value.getDouble("y") : 0;
view.reactScrollTo((int) PixelUtil.toPixelFromDIP(x), (int) PixelUtil.toPixelFromDIP(y));
} else {
view.reactScrollTo(0, 0);
}
}
}

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

@ -311,6 +311,8 @@ public class ReactScrollViewManager extends ViewGroupManager<ReactScrollView>
double x = value.hasKey("x") ? value.getDouble("x") : 0;
double y = value.hasKey("y") ? value.getDouble("y") : 0;
view.reactScrollTo((int) PixelUtil.toPixelFromDIP(x), (int) PixelUtil.toPixelFromDIP(y));
} else {
view.reactScrollTo(0, 0);
}
}

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

@ -7,6 +7,7 @@
package com.facebook.react.views.text;
import android.text.Layout;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.util.Linkify;
@ -96,6 +97,24 @@ public abstract class ReactTextAnchorViewManager<T extends View, C extends React
}
}
@ReactProp(name = "android_hyphenationFrequency")
public void setAndroidHyphenationFrequency(ReactTextView view, @Nullable String frequency) {
if (frequency == null || frequency.equals("none")) {
view.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
} else if (frequency.equals("full")) {
view.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
} else if (frequency.equals("balanced")) {
view.setHyphenationFrequency(Layout.BREAK_STRATEGY_BALANCED);
} else if (frequency.equals("high")) {
view.setHyphenationFrequency(Layout.BREAK_STRATEGY_HIGH_QUALITY);
} else if (frequency.equals("normal")) {
view.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
} else {
throw new JSApplicationIllegalArgumentException(
"Invalid android_hyphenationFrequency: " + frequency);
}
}
@ReactPropGroup(
names = {
ViewProps.BORDER_RADIUS,

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

@ -860,6 +860,19 @@ public class NativeAnimatedNodeTraversalTest {
verifyNoMoreInteractions(animationCallback);
}
@Test
public void testGetValue() {
int tag = 1;
mNativeAnimatedNodesManager.createAnimatedNode(
tag, JavaOnlyMap.of("type", "value", "value", 1d, "offset", 0d));
Callback saveValueCallbackMock = mock(Callback.class);
mNativeAnimatedNodesManager.getValue(tag, saveValueCallbackMock);
verify(saveValueCallbackMock, times(1)).invoke(1d);
}
@Test
public void testInterpolationNode() {
mNativeAnimatedNodesManager.createAnimatedNode(

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

@ -521,8 +521,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
mutation.type == ShadowViewMutation::Type::Remove
? mutation.oldChildShadowView
: mutation.newChildShadowView);
auto const &componentDescriptor =
getComponentDescriptorForShadowView(baselineShadowView);
bool haveComponentDescriptor =
hasComponentDescriptorForShadowView(baselineShadowView);
auto mutationConfig =
(mutation.type == ShadowViewMutation::Type::Delete
@ -660,8 +660,11 @@ LayoutAnimationKeyFrameManager::pullTransaction(
AnimationKeyFrame keyFrame{};
if (mutation.type == ShadowViewMutation::Type::Insert) {
if (mutationConfig->animationProperty ==
AnimationProperty::Opacity) {
auto props = componentDescriptor.cloneProps(viewStart.props, {});
AnimationProperty::Opacity &&
haveComponentDescriptor) {
auto props =
getComponentDescriptorForShadowView(baselineShadowView)
.cloneProps(viewStart.props, {});
const auto viewProps =
dynamic_cast<const ViewProps *>(props.get());
if (viewProps != nullptr) {
@ -675,8 +678,10 @@ LayoutAnimationKeyFrameManager::pullTransaction(
bool isScaleY = mutationConfig->animationProperty ==
AnimationProperty::ScaleY ||
mutationConfig->animationProperty == AnimationProperty::ScaleXY;
if (isScaleX || isScaleY) {
auto props = componentDescriptor.cloneProps(viewStart.props, {});
if ((isScaleX || isScaleY) && haveComponentDescriptor) {
auto props =
getComponentDescriptorForShadowView(baselineShadowView)
.cloneProps(viewStart.props, {});
const auto viewProps =
dynamic_cast<const ViewProps *>(props.get());
if (viewProps != nullptr) {
@ -695,8 +700,11 @@ LayoutAnimationKeyFrameManager::pullTransaction(
0};
} else if (mutation.type == ShadowViewMutation::Type::Delete) {
if (mutationConfig->animationProperty ==
AnimationProperty::Opacity) {
auto props = componentDescriptor.cloneProps(viewFinal.props, {});
AnimationProperty::Opacity &&
haveComponentDescriptor) {
auto props =
getComponentDescriptorForShadowView(baselineShadowView)
.cloneProps(viewFinal.props, {});
const auto viewProps =
dynamic_cast<const ViewProps *>(props.get());
if (viewProps != nullptr) {
@ -710,8 +718,10 @@ LayoutAnimationKeyFrameManager::pullTransaction(
bool isScaleY = mutationConfig->animationProperty ==
AnimationProperty::ScaleY ||
mutationConfig->animationProperty == AnimationProperty::ScaleXY;
if (isScaleX || isScaleY) {
auto props = componentDescriptor.cloneProps(viewFinal.props, {});
if ((isScaleX || isScaleY) && haveComponentDescriptor) {
auto props =
getComponentDescriptorForShadowView(baselineShadowView)
.cloneProps(viewFinal.props, {});
const auto viewProps =
dynamic_cast<const ViewProps *>(props.get());
if (viewProps != nullptr) {
@ -983,6 +993,12 @@ bool LayoutAnimationKeyFrameManager::mutatedViewIsVirtual(
return viewIsVirtual;
}
bool LayoutAnimationKeyFrameManager::hasComponentDescriptorForShadowView(
ShadowView const &shadowView) const {
return componentDescriptorRegistry_->hasComponentDescriptorAt(
shadowView.componentHandle);
}
ComponentDescriptor const &
LayoutAnimationKeyFrameManager::getComponentDescriptorForShadowView(
ShadowView const &shadowView) const {
@ -1008,6 +1024,9 @@ ShadowView LayoutAnimationKeyFrameManager::createInterpolatedShadowView(
AnimationConfig const &animationConfig,
ShadowView startingView,
ShadowView finalView) const {
if (!hasComponentDescriptorForShadowView(startingView)) {
return finalView;
}
ComponentDescriptor const &componentDescriptor =
getComponentDescriptorForShadowView(startingView);
auto mutatedShadowView = ShadowView(startingView);

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

@ -148,6 +148,7 @@ class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
protected:
bool mutatedViewIsVirtual(ShadowViewMutation const &mutation) const;
bool hasComponentDescriptorForShadowView(ShadowView const &shadowView) const;
ComponentDescriptor const &getComponentDescriptorForShadowView(
ShadowView const &shadowView) const;
std::pair<double, double> calculateAnimationProgress(

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

@ -168,6 +168,18 @@ ComponentDescriptor const &ComponentDescriptorRegistry::at(
return *_registryByHandle.at(componentHandle);
}
bool ComponentDescriptorRegistry::hasComponentDescriptorAt(
ComponentHandle componentHandle) const {
std::shared_lock<better::shared_mutex> lock(mutex_);
auto iterator = _registryByHandle.find(componentHandle);
if (iterator == _registryByHandle.end()) {
return false;
}
return true;
}
SharedShadowNode ComponentDescriptorRegistry::createNode(
Tag tag,
std::string const &viewName,

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

@ -51,6 +51,8 @@ class ComponentDescriptorRegistry {
ComponentDescriptor const &at(std::string const &componentName) const;
ComponentDescriptor const &at(ComponentHandle componentHandle) const;
bool hasComponentDescriptorAt(ComponentHandle componentHandle) const;
ShadowNode::Shared createNode(
Tag tag,
std::string const &viewName,

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

@ -0,0 +1,47 @@
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_preprocessor_flags_for_build_mode")
load(
"//tools/build_defs/oss:rn_defs.bzl",
"APPLE",
"get_apple_compiler_flags",
"get_apple_inspector_flags",
"react_native_xplat_target",
"rn_xplat_cxx_library",
"subdir_glob",
)
APPLE_COMPILER_FLAGS = get_apple_compiler_flags()
rn_xplat_cxx_library(
name = "inputaccessory",
srcs = glob(
["**/*.cpp"],
),
headers = [],
header_namespace = "",
exported_headers = subdir_glob(
[
("", "*.h"),
],
prefix = "react/components/inputaccessory",
),
compiler_flags = [
"-fexceptions",
"-frtti",
"-std=c++14",
"-Wall",
],
fbobjc_compiler_flags = APPLE_COMPILER_FLAGS,
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
force_static = True,
labels = ["supermodule:xplat/default/public.react_native.infra"],
platforms = (APPLE),
preprocessor_flags = [
"-DLOG_TAG=\"ReactNative\"",
"-DWITH_FBSYSTRACE=1",
],
visibility = ["PUBLIC"],
deps = [
react_native_xplat_target("fabric/core:core"),
"//xplat/js/react-native-github:generated_components-rncore",
],
)

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

@ -0,0 +1,48 @@
/*
* 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.
*/
#pragma once
#include <react/components/inputaccessory/InputAccessoryShadowNode.h>
#include <react/core/ConcreteComponentDescriptor.h>
namespace facebook {
namespace react {
/*
* Descriptor for <InputAccessoryView> component.
*/
class InputAccessoryComponentDescriptor final
: public ConcreteComponentDescriptor<InputAccessoryShadowNode> {
public:
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
void adopt(UnsharedShadowNode shadowNode) const override {
assert(std::dynamic_pointer_cast<InputAccessoryShadowNode>(shadowNode));
auto concreteShadowNode =
std::static_pointer_cast<InputAccessoryShadowNode>(shadowNode);
assert(std::dynamic_pointer_cast<YogaLayoutableShadowNode>(
concreteShadowNode));
auto layoutableShadowNode =
std::static_pointer_cast<YogaLayoutableShadowNode>(concreteShadowNode);
auto state =
std::static_pointer_cast<const InputAccessoryShadowNode::ConcreteState>(
shadowNode->getState());
auto stateData = state->getData();
layoutableShadowNode->setSize(
Size{stateData.screenSize.width, stateData.screenSize.height});
layoutableShadowNode->setPositionType(YGPositionTypeAbsolute);
ConcreteComponentDescriptor::adopt(shadowNode);
}
};
} // namespace react
} // namespace facebook

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

@ -0,0 +1,16 @@
/*
* 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 "InputAccessoryShadowNode.h"
namespace facebook {
namespace react {
extern const char InputAccessoryComponentName[] = "InputAccessoryView";
} // namespace react
} // namespace facebook

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

@ -0,0 +1,39 @@
/*
* 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.
*/
#pragma once
#include <react/components/inputaccessory/InputAccessoryState.h>
#include <react/components/rncore/EventEmitters.h>
#include <react/components/rncore/Props.h>
#include <react/components/view/ConcreteViewShadowNode.h>
namespace facebook {
namespace react {
extern const char InputAccessoryComponentName[];
/*
* `ShadowNode` for <InputAccessory> component.
*/
class InputAccessoryShadowNode final : public ConcreteViewShadowNode<
InputAccessoryComponentName,
InputAccessoryProps,
InputAccessoryEventEmitter,
InputAccessoryState> {
public:
using ConcreteViewShadowNode::ConcreteViewShadowNode;
static ShadowNodeTraits BaseTraits() {
auto traits = ConcreteViewShadowNode::BaseTraits();
traits.set(ShadowNodeTraits::Trait::RootNodeKind);
return traits;
}
};
} // namespace react
} // namespace facebook

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