Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'[skip ci] [RN][JS] BridgelessUIManager: Finish focus, blur #42210

Closed
wants to merge 9 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import UIManager from '../../ReactNative/UIManager';
import nullthrows from 'nullthrows';

/**
* This is a function exposed to the React Renderer that can be used by the
Expand All @@ -19,13 +20,13 @@ function legacySendAccessibilityEvent(
eventType: string,
): void {
if (eventType === 'focus') {
UIManager.sendAccessibilityEvent(
nullthrows(UIManager.sendAccessibilityEvent)(
reactTag,
UIManager.getConstants().AccessibilityEventTypes.typeViewFocused,
);
}
if (eventType === 'click') {
UIManager.sendAccessibilityEvent(
nullthrows(UIManager.sendAccessibilityEvent)(
reactTag,
UIManager.getConstants().AccessibilityEventTypes.typeViewClicked,
);
Expand Down
242 changes: 167 additions & 75 deletions packages/react-native/Libraries/ReactNative/BridgelessUIManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import type {RootTag} from '../Types/RootTagTypes';
import type {UIManagerJSInterface} from '../Types/UIManagerJSInterface';

import {unstable_hasComponent} from '../NativeComponent/NativeComponentRegistryUnstable';
import Platform from '../Utilities/Platform';
import {getFabricUIManager} from './FabricUIManager';
import nullthrows from 'nullthrows';

function raiseSoftError(methodName: string, details?: string): void {
Expand Down Expand Up @@ -96,15 +98,172 @@ const UIManagerJSOverridenAPIs = {
},
};

/**
* Leave Unimplemented: The only thing that called these methods was the paper renderer.
* In OSS, the New Architecture will just use the Fabric renderer, which uses
* different APIs.
*/
const UIManagerJSUnusedAPIs = {
createView: (
reactTag: ?number,
viewName: string,
rootTag: RootTag,
props: Object,
): void => {
raiseSoftError('createView');
},
updateView: (reactTag: number, viewName: string, props: Object): void => {
raiseSoftError('updateView');
},
setChildren: (containerTag: ?number, reactTags: Array<number>): void => {
raiseSoftError('setChildren');
},
manageChildren: (
containerTag: ?number,
moveFromIndices: Array<number>,
moveToIndices: Array<number>,
addChildReactTags: Array<number>,
addAtIndices: Array<number>,
removeAtIndices: Array<number>,
): void => {
raiseSoftError('manageChildren');
},
};

const UIManagerJSPlatformAPIs = Platform.select({
android: {
getConstantsForViewManager: (viewManagerName: string): Object => {
raiseSoftError('getConstantsForViewManager');
return {};
},
getDefaultEventTypes: (): Array<string> => {
raiseSoftError('getDefaultEventTypes');
return [];
},
setLayoutAnimationEnabledExperimental: (enabled: boolean): void => {
/**
* Layout animations are always enabled in the New Architecture.
* They cannot be turned off.
*/
if (!enabled) {
raiseSoftError(
'setLayoutAnimationEnabledExperimental(false)',
'Layout animations are always enabled in the New Architecture.',
);
}
},
sendAccessibilityEvent: (reactTag: ?number, eventType: number): void => {
if (reactTag == null) {
console.error(
`sendAccessibilityEvent() dropping event: Cannot be called with ${String(
reactTag,
)} reactTag`,
);
return;
}

// Keep this in sync with java:FabricUIManager.sendAccessibilityEventFromJS
// and legacySendAccessibilityEvent.android.js
const AccessibilityEvent = {
TYPE_VIEW_FOCUSED: 0x00000008,
TYPE_WINDOW_STATE_CHANGED: 0x00000020,
TYPE_VIEW_CLICKED: 0x00000001,
TYPE_VIEW_HOVER_ENTER: 0x00000080,
};

let eventName = null;
if (eventType === AccessibilityEvent.TYPE_VIEW_FOCUSED) {
eventName = 'focus';
} else if (eventType === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
eventName = 'windowStateChange';
} else if (eventType === AccessibilityEvent.TYPE_VIEW_CLICKED) {
eventName = 'click';
} else if (eventType === AccessibilityEvent.TYPE_VIEW_HOVER_ENTER) {
eventName = 'viewHoverEnter';
} else {
console.error(
`sendAccessibilityEvent() dropping event: Called with unsupported eventType: ${eventType}`,
);
return;
}

const FabricUIManager = nullthrows(getFabricUIManager());
const shadowNode =
FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
if (!shadowNode) {
console.error(
`sendAccessibilityEvent() dropping event: Cannot find view with tag #${reactTag}`,
);
return;
}

FabricUIManager.sendAccessibilityEvent(shadowNode, eventName);
},
showPopupMenu: (
reactTag: ?number,
items: Array<string>,
error: (error: Object) => void,
success: (event: string, selected?: number) => void,
): void => {
raiseSoftError('showPopupMenu');
},
dismissPopupMenu: (): void => {
raiseSoftError('dismissPopupMenu');
},
},
ios: {
lazilyLoadView: (name: string): Object => {
raiseSoftError('lazilyLoadView');
return {};
},
focus: (reactTag: ?number): void => {
if (reactTag == null) {
console.error(
`focus() noop: Cannot be called with ${String(reactTag)} reactTag`,
);
return;
}

const FabricUIManager = nullthrows(getFabricUIManager());
const shadowNode =
FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
if (!shadowNode) {
console.error(`focus() noop: Cannot find view with tag #${reactTag}`);
return;
}
FabricUIManager.dispatchCommand(shadowNode, 'focus', []);
},
blur: (reactTag: ?number): void => {
if (reactTag == null) {
console.error(
`blur() noop: Cannot be called with ${String(reactTag)} reactTag`,
);
return;
}

const FabricUIManager = nullthrows(getFabricUIManager());
const shadowNode =
FabricUIManager.findShadowNodeByTag_DEPRECATED(reactTag);
if (!shadowNode) {
console.error(`blur() noop: Cannot find view with tag #${reactTag}`);
return;
}
FabricUIManager.dispatchCommand(shadowNode, 'blur', []);
},
},
});

const UIManagerJS: UIManagerJSInterface & {[string]: any} = {
...UIManagerJSOverridenAPIs,
...UIManagerJSPlatformAPIs,
...UIManagerJSUnusedAPIs,
getViewManagerConfig: (viewManagerName: string): mixed => {
if (getUIManagerConstants) {
return getUIManagerConstantsCache()[viewManagerName];
} else {
raiseSoftError(
'getViewManagerConfig',
`Use hasViewManagerConfig instead. viewManagerName: ${viewManagerName}`,
`getViewManagerConfig('${viewManagerName}')`,
`If '${viewManagerName}' has a ViewManager and you want to retrieve its native ViewConfig, please turn on the native ViewConfig interop layer. If you want to see if this component is registered with React Native, please call hasViewManagerConfig('${viewManagerName}') instead.`,
);
return null;
}
Expand All @@ -120,35 +279,6 @@ const UIManagerJS: UIManagerJSInterface & {[string]: any} = {
return null;
}
},
getConstantsForViewManager: (viewManagerName: string): Object => {
raiseSoftError('getConstantsForViewManager');
return {};
},
getDefaultEventTypes: (): Array<string> => {
raiseSoftError('getDefaultEventTypes');
return [];
},
lazilyLoadView: (name: string): Object => {
raiseSoftError('lazilyLoadView');
return {};
},
createView: (
reactTag: ?number,
viewName: string,
rootTag: RootTag,
props: Object,
): void => {
raiseSoftError('createView');
},
updateView: (reactTag: number, viewName: string, props: Object): void => {
raiseSoftError('updateView');
},
focus: (reactTag: ?number): void => {
raiseSoftError('focus');
},
blur: (reactTag: ?number): void => {
raiseSoftError('blur');
},
findSubviewIn: (
reactTag: ?number,
point: Array<number>,
Expand Down Expand Up @@ -180,50 +310,12 @@ const UIManagerJS: UIManagerJSInterface & {[string]: any} = {
callback: () => void,
errorCallback: (error: Object) => void,
): void => {
raiseSoftError('configureNextLayoutAnimation');
},
removeSubviewsFromContainerWithID: (containerID: number): void => {
raiseSoftError('removeSubviewsFromContainerWithID');
},
replaceExistingNonRootView: (
reactTag: ?number,
newReactTag: ?number,
): void => {
raiseSoftError('replaceExistingNonRootView');
},
setChildren: (containerTag: ?number, reactTags: Array<number>): void => {
raiseSoftError('setChildren');
},
manageChildren: (
containerTag: ?number,
moveFromIndices: Array<number>,
moveToIndices: Array<number>,
addChildReactTags: Array<number>,
addAtIndices: Array<number>,
removeAtIndices: Array<number>,
): void => {
raiseSoftError('manageChildren');
},

// Android only
setLayoutAnimationEnabledExperimental: (enabled: boolean): void => {
raiseSoftError('setLayoutAnimationEnabledExperimental');
},
// Please use AccessibilityInfo.sendAccessibilityEvent instead.
// See SetAccessibilityFocusExample in AccessibilityExample.js for a migration example.
sendAccessibilityEvent: (reactTag: ?number, eventType: number): void => {
raiseSoftError('sendAccessibilityEvent');
},
showPopupMenu: (
reactTag: ?number,
items: Array<string>,
error: (error: Object) => void,
success: (event: string, selected?: number) => void,
): void => {
raiseSoftError('showPopupMenu');
},
dismissPopupMenu: (): void => {
raiseSoftError('dismissPopupMenu');
const FabricUIManager = nullthrows(getFabricUIManager());
FabricUIManager.configureNextLayoutAnimation(
config,
callback,
errorCallback,
);
},
};

Expand Down
25 changes: 11 additions & 14 deletions packages/react-native/Libraries/ReactNative/NativeUIManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,13 @@ import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';

export interface Spec extends TurboModule {
+getConstants: () => Object;
+getConstantsForViewManager: (viewManagerName: string) => Object;
+getDefaultEventTypes: () => Array<string>;
+lazilyLoadView: (name: string) => Object; // revisit return
+createView: (
reactTag: ?number,
viewName: string,
rootTag: RootTag,
props: Object,
) => void;
+updateView: (reactTag: number, viewName: string, props: Object) => void;
+focus: (reactTag: ?number) => void;
+blur: (reactTag: ?number) => void;
+findSubviewIn: (
reactTag: ?number,
point: Array<number>,
Expand Down Expand Up @@ -91,11 +86,6 @@ export interface Spec extends TurboModule {
callback: () => void, // check what is returned here
errorCallback: (error: Object) => void,
) => void;
+removeSubviewsFromContainerWithID: (containerID: number) => void;
+replaceExistingNonRootView: (
reactTag: ?number,
newReactTag: ?number,
) => void;
+setChildren: (containerTag: ?number, reactTags: Array<number>) => void;
+manageChildren: (
containerTag: ?number,
Expand All @@ -107,15 +97,22 @@ export interface Spec extends TurboModule {
) => void;

// Android only
+setLayoutAnimationEnabledExperimental: (enabled: boolean) => void;
+sendAccessibilityEvent: (reactTag: ?number, eventType: number) => void;
+showPopupMenu: (
+getConstantsForViewManager?: (viewManagerName: string) => Object;
+getDefaultEventTypes?: () => Array<string>;
+setLayoutAnimationEnabledExperimental?: (enabled: boolean) => void;
+sendAccessibilityEvent?: (reactTag: ?number, eventType: number) => void;
+showPopupMenu?: (
reactTag: ?number,
items: Array<string>,
error: (error: Object) => void,
success: (event: string, selected?: number) => void,
) => void;
+dismissPopupMenu: () => void;
+dismissPopupMenu?: () => void;

// ios only
+lazilyLoadView?: (name: string) => Object; // revisit return
+focus?: (reactTag: ?number) => void;
+blur?: (reactTag: ?number) => void;
}

export default (TurboModuleRegistry.getEnforcing<Spec>('UIManager'): Spec);
6 changes: 4 additions & 2 deletions packages/react-native/Libraries/ReactNative/PaperUIManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {RootTag} from '../Types/RootTagTypes';
import type {UIManagerJSInterface} from '../Types/UIManagerJSInterface';

import NativeUIManager from './NativeUIManager';
import nullthrows from 'nullthrows';

const NativeModules = require('../BatchedBridge/NativeModules');
const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty');
Expand Down Expand Up @@ -67,7 +68,7 @@ function getViewManagerConfig(viewManagerName: string): any {
NativeUIManager.lazilyLoadView &&
!triedLoadingConfig.has(viewManagerName)
) {
const result = NativeUIManager.lazilyLoadView(viewManagerName);
const result = nullthrows(NativeUIManager.lazilyLoadView)(viewManagerName);
triedLoadingConfig.add(viewManagerName);
if (result != null && result.viewConfig != null) {
getConstants()[viewManagerName] = result.viewConfig;
Expand Down Expand Up @@ -161,7 +162,8 @@ if (Platform.OS === 'ios') {
} else if (getConstants().ViewManagerNames) {
NativeUIManager.getConstants().ViewManagerNames.forEach(viewManagerName => {
defineLazyObjectProperty(NativeUIManager, viewManagerName, {
get: () => NativeUIManager.getConstantsForViewManager(viewManagerName),
get: () =>
nullthrows(NativeUIManager.getConstantsForViewManager)(viewManagerName),
});
});
}
Expand Down
Loading
Loading