feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import DOMRect from '../webapis/dom/geometry/DOMRect';
import DOMRectReadOnly from '../webapis/dom/geometry/DOMRectReadOnly';
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it
global.DOMRect = DOMRect;
// $FlowExpectedError[cannot-write] The global isn't writable anywhere but here, where we define it
global.DOMRectReadOnly = DOMRectReadOnly;

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8509d5ee87efb5aa8da7efcd2085d0a2>>
* @flow strict-local
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
import type {TurboModule} from '../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+commonTestFlag?: () => boolean;
+enableBackgroundExecutor?: () => boolean;
+useModernRuntimeScheduler?: () => boolean;
+enableMicrotasks?: () => boolean;
+batchRenderingUpdatesInEventLoop?: () => boolean;
+enableSpannableBuildingUnification?: () => boolean;
+enableCustomDrawOrderFabric?: () => boolean;
+enableFixForClippedSubviewsCrash?: () => boolean;
+inspectorEnableCxxInspectorPackagerConnection?: () => boolean;
+inspectorEnableModernCDPRegistry?: () => boolean;
}
const NativeReactNativeFeatureFlags: ?Spec = TurboModuleRegistry.get<Spec>(
'NativeReactNativeFeatureFlagsCxx',
);
export default NativeReactNativeFeatureFlags;

View File

@@ -0,0 +1,140 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7c83d5613c3be517efe48378e6356e79>>
* @flow strict-local
*/
/**
* IMPORTANT: Do NOT modify this file directly.
*
* To change the definition of the flags, edit
* packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js.
*
* To regenerate this code, run the following script from the repo root:
* yarn featureflags-update
*/
import {
type Getter,
createJavaScriptFlagGetter,
createNativeFlagGetter,
setOverrides,
} from './ReactNativeFeatureFlagsBase';
export type ReactNativeFeatureFlagsJsOnly = {
jsOnlyTestFlag: Getter<boolean>,
isLayoutAnimationEnabled: Getter<boolean>,
animatedShouldDebounceQueueFlush: Getter<boolean>,
animatedShouldUseSingleOp: Getter<boolean>,
enableAccessToHostTreeInFabric: Getter<boolean>,
shouldUseAnimatedObjectForTransform: Getter<boolean>,
shouldUseSetNativePropsInFabric: Getter<boolean>,
shouldUseRemoveClippedSubviewsAsDefaultOnIOS: Getter<boolean>,
};
export type ReactNativeFeatureFlagsJsOnlyOverrides = Partial<ReactNativeFeatureFlagsJsOnly>;
export type ReactNativeFeatureFlags = {
...ReactNativeFeatureFlagsJsOnly,
commonTestFlag: Getter<boolean>,
enableBackgroundExecutor: Getter<boolean>,
useModernRuntimeScheduler: Getter<boolean>,
enableMicrotasks: Getter<boolean>,
batchRenderingUpdatesInEventLoop: Getter<boolean>,
enableSpannableBuildingUnification: Getter<boolean>,
enableCustomDrawOrderFabric: Getter<boolean>,
enableFixForClippedSubviewsCrash: Getter<boolean>,
inspectorEnableCxxInspectorPackagerConnection: Getter<boolean>,
inspectorEnableModernCDPRegistry: Getter<boolean>,
}
/**
* JS-only flag for testing. Do NOT modify.
*/
export const jsOnlyTestFlag: Getter<boolean> = createJavaScriptFlagGetter('jsOnlyTestFlag', false);
/**
* Function used to enable / disabled Layout Animations in React Native.
*/
export const isLayoutAnimationEnabled: Getter<boolean> = createJavaScriptFlagGetter('isLayoutAnimationEnabled', true);
/**
* Enables an experimental flush-queue debouncing in Animated.js.
*/
export const animatedShouldDebounceQueueFlush: Getter<boolean> = createJavaScriptFlagGetter('animatedShouldDebounceQueueFlush', false);
/**
* Enables an experimental mega-operation for Animated.js that replaces many calls to native with a single call into native, to reduce JSI/JNI traffic.
*/
export const animatedShouldUseSingleOp: Getter<boolean> = createJavaScriptFlagGetter('animatedShouldUseSingleOp', false);
/**
* Enables access to the host tree in Fabric using DOM-compatible APIs.
*/
export const enableAccessToHostTreeInFabric: Getter<boolean> = createJavaScriptFlagGetter('enableAccessToHostTreeInFabric', false);
/**
* Enables use of AnimatedObject for animating transform values.
*/
export const shouldUseAnimatedObjectForTransform: Getter<boolean> = createJavaScriptFlagGetter('shouldUseAnimatedObjectForTransform', false);
/**
* Enables use of setNativeProps in JS driven animations.
*/
export const shouldUseSetNativePropsInFabric: Getter<boolean> = createJavaScriptFlagGetter('shouldUseSetNativePropsInFabric', true);
/**
* removeClippedSubviews prop will be used as the default in FlatList on iOS to match Android
*/
export const shouldUseRemoveClippedSubviewsAsDefaultOnIOS: Getter<boolean> = createJavaScriptFlagGetter('shouldUseRemoveClippedSubviewsAsDefaultOnIOS', false);
/**
* Common flag for testing. Do NOT modify.
*/
export const commonTestFlag: Getter<boolean> = createNativeFlagGetter('commonTestFlag', false);
/**
* Enables the use of a background executor to compute layout and commit updates on Fabric (this system is deprecated and should not be used).
*/
export const enableBackgroundExecutor: Getter<boolean> = createNativeFlagGetter('enableBackgroundExecutor', false);
/**
* When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread.
*/
export const useModernRuntimeScheduler: Getter<boolean> = createNativeFlagGetter('useModernRuntimeScheduler', false);
/**
* Enables the use of microtasks in Hermes (scheduling) and RuntimeScheduler (execution).
*/
export const enableMicrotasks: Getter<boolean> = createNativeFlagGetter('enableMicrotasks', false);
/**
* When enabled, the RuntimeScheduler processing the event loop will batch all rendering updates and dispatch them together at the end of each iteration of the loop.
*/
export const batchRenderingUpdatesInEventLoop: Getter<boolean> = createNativeFlagGetter('batchRenderingUpdatesInEventLoop', false);
/**
* Uses new, deduplicated logic for constructing Android Spannables from text fragments
*/
export const enableSpannableBuildingUnification: Getter<boolean> = createNativeFlagGetter('enableSpannableBuildingUnification', false);
/**
* When enabled, Fabric will use customDrawOrder in ReactViewGroup (similar to old architecture).
*/
export const enableCustomDrawOrderFabric: Getter<boolean> = createNativeFlagGetter('enableCustomDrawOrderFabric', false);
/**
* Attempt at fixing a crash related to subview clipping on Android. This is a kill switch for the fix
*/
export const enableFixForClippedSubviewsCrash: Getter<boolean> = createNativeFlagGetter('enableFixForClippedSubviewsCrash', false);
/**
* Flag determining if the C++ implementation of InspectorPackagerConnection should be used instead of the per-platform one. This flag is global and should not be changed across React Host lifetimes.
*/
export const inspectorEnableCxxInspectorPackagerConnection: Getter<boolean> = createNativeFlagGetter('inspectorEnableCxxInspectorPackagerConnection', false);
/**
* Flag determining if the modern CDP backend should be enabled. This flag is global and should not be changed across React Host lifetimes.
*/
export const inspectorEnableModernCDPRegistry: Getter<boolean> = createNativeFlagGetter('inspectorEnableModernCDPRegistry', false);
/**
* Overrides the feature flags with the provided methods.
* NOTE: Only JS-only flags can be overridden from JavaScript using this API.
*/
export const override = setOverrides;

View File

@@ -0,0 +1,84 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
*/
import type {
ReactNativeFeatureFlagsJsOnly,
ReactNativeFeatureFlagsJsOnlyOverrides,
} from './ReactNativeFeatureFlags';
import NativeReactNativeFeatureFlags from './NativeReactNativeFeatureFlags';
const accessedFeatureFlags: Set<string> = new Set();
let overrides: ?ReactNativeFeatureFlagsJsOnlyOverrides;
export type Getter<T> = () => T;
function createGetter<T: boolean | number | string>(
configName: string,
customValueGetter: Getter<?T>,
defaultValue: T,
): Getter<T> {
let cachedValue: ?T;
return () => {
if (cachedValue == null) {
accessedFeatureFlags.add(configName);
cachedValue = customValueGetter() ?? defaultValue;
}
return cachedValue;
};
}
export function createJavaScriptFlagGetter<
K: $Keys<ReactNativeFeatureFlagsJsOnly>,
>(
configName: K,
defaultValue: ReturnType<ReactNativeFeatureFlagsJsOnly[K]>,
): Getter<ReturnType<ReactNativeFeatureFlagsJsOnly[K]>> {
return createGetter(
configName,
() => overrides?.[configName]?.(),
defaultValue,
);
}
type NativeFeatureFlags = $NonMaybeType<typeof NativeReactNativeFeatureFlags>;
export function createNativeFlagGetter<K: $Keys<NativeFeatureFlags>>(
configName: K,
defaultValue: ReturnType<$NonMaybeType<NativeFeatureFlags[K]>>,
): Getter<ReturnType<$NonMaybeType<NativeFeatureFlags[K]>>> {
return createGetter(
configName,
() => NativeReactNativeFeatureFlags?.[configName]?.(),
defaultValue,
);
}
export function getOverrides(): ?ReactNativeFeatureFlagsJsOnlyOverrides {
return overrides;
}
export function setOverrides(
newOverrides: ReactNativeFeatureFlagsJsOnlyOverrides,
): void {
if (overrides != null) {
throw new Error('Feature flags cannot be overridden more than once');
}
if (accessedFeatureFlags.size > 0) {
const accessedFeatureFlagsStr = Array.from(accessedFeatureFlags).join(', ');
throw new Error(
`Feature flags were accessed before being overridden: ${accessedFeatureFlagsStr}`,
);
}
overrides = newOverrides;
}

View File

@@ -0,0 +1,92 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
* @oncall react_native
*/
describe('ReactNativeFeatureFlags', () => {
beforeEach(() => {
jest.resetModules();
});
it('should provide default values for common flags if the native module is NOT available', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
expect(ReactNativeFeatureFlags.commonTestFlag()).toBe(false);
});
it('should access and cache common flags from the native module if it is available', () => {
const commonTestFlagFn = jest.fn(() => true);
jest.doMock('../NativeReactNativeFeatureFlags', () => ({
__esModule: true,
default: {
commonTestFlag: commonTestFlagFn,
},
}));
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
expect(commonTestFlagFn).toHaveBeenCalledTimes(0);
expect(ReactNativeFeatureFlags.commonTestFlag()).toBe(true);
expect(commonTestFlagFn).toHaveBeenCalledTimes(1);
expect(ReactNativeFeatureFlags.commonTestFlag()).toBe(true);
expect(commonTestFlagFn).toHaveBeenCalledTimes(1);
});
it('should provide default values for JS-only flags', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
expect(ReactNativeFeatureFlags.jsOnlyTestFlag()).toBe(false);
});
it('should access and cache overridden JS-only flags', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
const jsOnlyTestFlagFn = jest.fn(() => true);
ReactNativeFeatureFlags.override({
jsOnlyTestFlag: jsOnlyTestFlagFn,
});
expect(jsOnlyTestFlagFn).toHaveBeenCalledTimes(0);
expect(ReactNativeFeatureFlags.jsOnlyTestFlag()).toBe(true);
expect(jsOnlyTestFlagFn).toHaveBeenCalledTimes(1);
expect(ReactNativeFeatureFlags.jsOnlyTestFlag()).toBe(true);
expect(jsOnlyTestFlagFn).toHaveBeenCalledTimes(1);
});
it('should throw an error if any of the flags has been accessed before overridding', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
ReactNativeFeatureFlags.commonTestFlag();
expect(() =>
ReactNativeFeatureFlags.override({
jsOnlyTestFlag: () => true,
}),
).toThrow(
'Feature flags were accessed before being overridden: commonTestFlag',
);
});
it('should throw an error when trying to set overrides twice', () => {
const ReactNativeFeatureFlags = require('../ReactNativeFeatureFlags');
ReactNativeFeatureFlags.override({
jsOnlyTestFlag: () => true,
});
expect(() =>
ReactNativeFeatureFlags.override({
jsOnlyTestFlag: () => false,
}),
).toThrow('Feature flags cannot be overridden more than once');
});
});

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import type {WithDefault} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
/**
* Whether the indicator should hide when not animating (true by default).
*
* See https://reactnative.dev/docs/activityindicator#hideswhenstopped-ios
*/
hidesWhenStopped?: WithDefault<boolean, true>,
/**
* Whether to show the indicator (true, the default) or hide it (false).
*
* See https://reactnative.dev/docs/activityindicator#animating
*/
animating?: WithDefault<boolean, true>,
/**
* The foreground color of the spinner (default is gray).
*
* See https://reactnative.dev/docs/activityindicator#color
*/
color?: ?ColorValue,
/**
* Size of the indicator (default is 'small').
* Passing a number to the size prop is only supported on Android.
*
* See https://reactnative.dev/docs/activityindicator#size
*/
size?: WithDefault<'small' | 'large', 'small'>,
|}>;
export default (codegenNativeComponent<NativeProps>('ActivityIndicatorView', {
paperComponentName: 'RCTActivityIndicatorView',
}): HostComponent<NativeProps>);

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import type {
DirectEventHandler,
Float,
Int32,
WithDefault,
} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeCommands from '../../../../Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
import * as React from 'react';
type DrawerStateEvent = $ReadOnly<{|
drawerState: Int32,
|}>;
type DrawerSlideEvent = $ReadOnly<{|
offset: Float,
|}>;
type NativeProps = $ReadOnly<{|
...ViewProps,
/**
* Determines whether the keyboard gets dismissed in response to a drag.
* - 'none' (the default), drags do not dismiss the keyboard.
* - 'on-drag', the keyboard is dismissed when a drag begins.
*/
keyboardDismissMode?: WithDefault<'none' | 'on-drag', 'none'>,
/**
* Specifies the background color of the drawer. The default value is white.
* If you want to set the opacity of the drawer, use rgba. Example:
*
* ```
* return (
* <DrawerLayoutAndroid drawerBackgroundColor="rgba(0,0,0,0.5)">
* </DrawerLayoutAndroid>
* );
* ```
*/
drawerBackgroundColor: ColorValue,
/**
* Specifies the side of the screen from which the drawer will slide in.
*/
drawerPosition?: WithDefault<'left' | 'right', 'left'>,
/**
* Specifies the width of the drawer, more precisely the width of the view that be pulled in
* from the edge of the window.
*/
drawerWidth?: WithDefault<Float, null>,
/**
* Specifies the lock mode of the drawer. The drawer can be locked in 3 states:
* - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures.
* - locked-closed, meaning that the drawer will stay closed and not respond to gestures.
* - locked-open, meaning that the drawer will stay opened and not respond to gestures.
* The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`).
*/
drawerLockMode?: WithDefault<
'unlocked' | 'locked-closed' | 'locked-open',
'unlocked',
>,
/**
* Function called whenever there is an interaction with the navigation view.
*/
onDrawerSlide?: ?DirectEventHandler<DrawerSlideEvent>,
/**
* Function called when the drawer state has changed. The drawer can be in 3 states:
* - Idle, meaning there is no interaction with the navigation view happening at the time
* - Dragging, meaning there is currently an interaction with the navigation view
* - Settling, meaning that there was an interaction with the navigation view, and the
* navigation view is now finishing its closing or opening animation
*/
onDrawerStateChanged?: ?DirectEventHandler<DrawerStateEvent>,
/**
* Function called whenever the navigation view has been opened.
*/
onDrawerOpen?: ?DirectEventHandler<null>,
/**
* Function called whenever the navigation view has been closed.
*/
onDrawerClose?: ?DirectEventHandler<null>,
/**
* Make the drawer take the entire screen and draw the background of the
* status bar to allow it to open over the status bar. It will only have an
* effect on API 21+.
*/
statusBarBackgroundColor?: ?ColorValue,
|}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+openDrawer: (viewRef: React.ElementRef<NativeType>) => void;
+closeDrawer: (viewRef: React.ElementRef<NativeType>) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['openDrawer', 'closeDrawer'],
});
export default (codegenNativeComponent<NativeProps>(
'AndroidDrawerLayout',
): NativeType);

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
removeClippedSubviews?: ?boolean,
|}>;
type NativeType = HostComponent<NativeProps>;
export default (codegenNativeComponent<NativeProps>(
'AndroidHorizontalScrollContentView',
): NativeType);

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import type {
DirectEventHandler,
Float,
WithDefault,
} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeCommands from '../../../../Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
import * as React from 'react';
type NativeProps = $ReadOnly<{|
...ViewProps,
/**
* Whether the pull to refresh functionality is enabled.
*/
enabled?: WithDefault<boolean, true>,
/**
* The colors (at least one) that will be used to draw the refresh indicator.
*/
colors?: ?$ReadOnlyArray<ColorValue>,
/**
* The background color of the refresh indicator.
*/
progressBackgroundColor?: ?ColorValue,
/**
* Size of the refresh indicator.
*/
size?: WithDefault<'default' | 'large', 'default'>,
/**
* Progress view top offset
*/
progressViewOffset?: WithDefault<Float, 0>,
/**
* Called when the view starts refreshing.
*/
onRefresh?: ?DirectEventHandler<null>,
/**
* Whether the view should be indicating an active refresh.
*/
refreshing: boolean,
|}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+setNativeRefreshing: (
viewRef: React.ElementRef<NativeType>,
value: boolean,
) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['setNativeRefreshing'],
});
export default (codegenNativeComponent<NativeProps>(
'AndroidSwipeRefreshLayout',
): NativeType);

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import type {
BubblingEventHandler,
Int32,
WithDefault,
} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeCommands from '../../../../Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
import * as React from 'react';
type SwitchChangeEvent = $ReadOnly<{|
value: boolean,
target: Int32,
|}>;
type NativeProps = $ReadOnly<{|
...ViewProps,
// Props
disabled?: WithDefault<boolean, false>,
enabled?: WithDefault<boolean, true>,
thumbColor?: ?ColorValue,
trackColorForFalse?: ?ColorValue,
trackColorForTrue?: ?ColorValue,
value?: WithDefault<boolean, false>,
on?: WithDefault<boolean, false>,
thumbTintColor?: ?ColorValue,
trackTintColor?: ?ColorValue,
// Events
onChange?: BubblingEventHandler<SwitchChangeEvent>,
|}>;
type NativeType = HostComponent<NativeProps>;
interface NativeCommands {
+setNativeValue: (
viewRef: React.ElementRef<NativeType>,
value: boolean,
) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['setNativeValue'],
});
export default (codegenNativeComponent<NativeProps>('AndroidSwitch', {
interfaceOnly: true,
}): NativeType);

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ProcessedColorValue} from '../../../../Libraries/StyleSheet/processColor';
import codegenNativeCommands from '../../../../Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
import * as React from 'react';
type NativeProps = $ReadOnly<{|
...ViewProps,
|}>;
export type DebuggingOverlayNativeComponentType = HostComponent<NativeProps>;
export type TraceUpdate = {
id: number,
rectangle: ElementRectangle,
color: ?ProcessedColorValue,
};
export type ElementRectangle = {
x: number,
y: number,
width: number,
height: number,
};
interface NativeCommands {
+highlightTraceUpdates: (
viewRef: React.ElementRef<DebuggingOverlayNativeComponentType>,
updates: $ReadOnlyArray<TraceUpdate>,
) => void;
+highlightElements: (
viewRef: React.ElementRef<DebuggingOverlayNativeComponentType>,
elements: $ReadOnlyArray<ElementRectangle>,
) => void;
+clearElementsHighlights: (
viewRef: React.ElementRef<DebuggingOverlayNativeComponentType>,
) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: [
'highlightTraceUpdates',
'highlightElements',
'clearElementsHighlights',
],
});
export default (codegenNativeComponent<NativeProps>(
'DebuggingOverlay',
): HostComponent<NativeProps>);

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import type {
Double,
WithDefault,
} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
//Props
styleAttr?: string,
typeAttr?: string,
indeterminate: boolean,
progress?: WithDefault<Double, 0>,
animating?: WithDefault<boolean, true>,
color?: ?ColorValue,
testID?: WithDefault<string, ''>,
|}>;
export default (codegenNativeComponent<NativeProps>('AndroidProgressBar', {
interfaceOnly: true,
}): HostComponent<NativeProps>);

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import type {
DirectEventHandler,
Float,
WithDefault,
} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeCommands from '../../../../Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
import * as React from 'react';
type NativeProps = $ReadOnly<{|
...ViewProps,
/**
* The color of the refresh indicator.
*/
tintColor?: ?ColorValue,
/**
* Title color.
*/
titleColor?: ?ColorValue,
/**
* The title displayed under the refresh indicator.
*/
title?: WithDefault<string, null>,
/**
* Progress view top offset
*/
progressViewOffset?: WithDefault<Float, 0>,
/**
* Called when the view starts refreshing.
*/
onRefresh?: ?DirectEventHandler<null>,
/**
* Whether the view should be indicating an active refresh.
*/
refreshing: boolean,
|}>;
type ComponentType = HostComponent<NativeProps>;
interface NativeCommands {
+setNativeRefreshing: (
viewRef: React.ElementRef<ComponentType>,
refreshing: boolean,
) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['setNativeRefreshing'],
});
export default (codegenNativeComponent<NativeProps>('PullToRefreshView', {
paperComponentName: 'RCTRefreshControl',
excludedPlatforms: ['android'],
}): HostComponent<NativeProps>);

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
backgroundColor?: ?ColorValue,
|}>;
export default (codegenNativeComponent<NativeProps>('InputAccessory', {
interfaceOnly: true,
paperComponentName: 'RCTInputAccessoryView',
excludedPlatforms: ['android'],
}): HostComponent<NativeProps>);

View File

@@ -0,0 +1,139 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {
DirectEventHandler,
Int32,
WithDefault,
} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
type OrientationChangeEvent = $ReadOnly<{|
orientation: 'portrait' | 'landscape',
|}>;
type NativeProps = $ReadOnly<{|
...ViewProps,
/**
* The `animationType` prop controls how the modal animates.
*
* See https://reactnative.dev/docs/modal#animationtype
*/
animationType?: WithDefault<'none' | 'slide' | 'fade', 'none'>,
/**
* The `presentationStyle` prop controls how the modal appears.
*
* See https://reactnative.dev/docs/modal#presentationstyle
*/
presentationStyle?: WithDefault<
'fullScreen' | 'pageSheet' | 'formSheet' | 'overFullScreen',
'fullScreen',
>,
/**
* The `transparent` prop determines whether your modal will fill the
* entire view.
*
* See https://reactnative.dev/docs/modal#transparent
*/
transparent?: WithDefault<boolean, false>,
/**
* The `statusBarTranslucent` prop determines whether your modal should go under
* the system statusbar.
*
* See https://reactnative.dev/docs/modal#statusBarTranslucent
*/
statusBarTranslucent?: WithDefault<boolean, false>,
/**
* The `hardwareAccelerated` prop controls whether to force hardware
* acceleration for the underlying window.
*
* See https://reactnative.dev/docs/modal#hardwareaccelerated
*/
hardwareAccelerated?: WithDefault<boolean, false>,
/**
* The `onRequestClose` callback is called when the user taps the hardware
* back button on Android or the menu button on Apple TV.
*
* This is required on Apple TV and Android.
*
* See https://reactnative.dev/docs/modal#onrequestclose
*/
onRequestClose?: ?DirectEventHandler<null>,
/**
* The `onShow` prop allows passing a function that will be called once the
* modal has been shown.
*
* See https://reactnative.dev/docs/modal#onshow
*/
onShow?: ?DirectEventHandler<null>,
/**
* The `onDismiss` prop allows passing a function that will be called once
* the modal has been dismissed.
*
* See https://reactnative.dev/docs/modal#ondismiss
*/
onDismiss?: ?DirectEventHandler<null>,
/**
* The `visible` prop determines whether your modal is visible.
*
* See https://reactnative.dev/docs/modal#visible
*/
visible?: WithDefault<boolean, false>,
/**
* Deprecated. Use the `animationType` prop instead.
*/
animated?: WithDefault<boolean, false>,
/**
* The `supportedOrientations` prop allows the modal to be rotated to any of the specified orientations.
*
* See https://reactnative.dev/docs/modal#supportedorientations
*/
supportedOrientations?: WithDefault<
$ReadOnlyArray<
| 'portrait'
| 'portrait-upside-down'
| 'landscape'
| 'landscape-left'
| 'landscape-right',
>,
'portrait',
>,
/**
* The `onOrientationChange` callback is called when the orientation changes while the modal is being displayed.
*
* See https://reactnative.dev/docs/modal#onorientationchange
*/
onOrientationChange?: ?DirectEventHandler<OrientationChangeEvent>,
/**
* The `identifier` is the unique number for identifying Modal components.
*/
identifier?: WithDefault<Int32, 0>,
|}>;
export default (codegenNativeComponent<NativeProps>('ModalHostView', {
interfaceOnly: true,
paperComponentName: 'RCTModalHostView',
}): HostComponent<NativeProps>);

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
// No props
|}>;
export default (codegenNativeComponent<NativeProps>('SafeAreaView', {
paperComponentName: 'RCTSafeAreaView',
interfaceOnly: true,
}): HostComponent<NativeProps>);

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ColorValue} from '../../../../Libraries/StyleSheet/StyleSheet';
import type {
BubblingEventHandler,
Int32,
WithDefault,
} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeCommands from '../../../../Libraries/Utilities/codegenNativeCommands';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
import * as React from 'react';
type SwitchChangeEvent = $ReadOnly<{|
value: boolean,
target: Int32,
|}>;
type NativeProps = $ReadOnly<{|
...ViewProps,
// Props
disabled?: WithDefault<boolean, false>,
value?: WithDefault<boolean, false>,
tintColor?: ?ColorValue,
onTintColor?: ?ColorValue,
thumbTintColor?: ?ColorValue,
// Deprecated props
thumbColor?: ?ColorValue,
trackColorForFalse?: ?ColorValue,
trackColorForTrue?: ?ColorValue,
// Events
onChange?: ?BubblingEventHandler<SwitchChangeEvent>,
|}>;
type ComponentType = HostComponent<NativeProps>;
interface NativeCommands {
+setValue: (viewRef: React.ElementRef<ComponentType>, value: boolean) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['setValue'],
});
export default (codegenNativeComponent<NativeProps>('Switch', {
paperComponentName: 'RCTSwitch',
excludedPlatforms: ['android'],
}): ComponentType);

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type {ViewProps} from '../../../../Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from '../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {WithDefault} from '../../../../Libraries/Types/CodegenTypes';
import codegenNativeComponent from '../../../../Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
name?: WithDefault<string, ''>,
|}>;
// NOTE: This component is not implemented in paper
// Do not require this file in paper builds
export default (codegenNativeComponent<NativeProps>(
'UnimplementedNativeView',
): HostComponent<NativeProps>);

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+isReduceMotionEnabled: (
onSuccess: (isReduceMotionEnabled: boolean) => void,
) => void;
+isTouchExplorationEnabled: (
onSuccess: (isScreenReaderEnabled: boolean) => void,
) => void;
+isAccessibilityServiceEnabled?: ?(
onSuccess: (isAccessibilityServiceEnabled: boolean) => void,
) => void;
+setAccessibilityFocus: (reactTag: number) => void;
+announceForAccessibility: (announcement: string) => void;
+getRecommendedTimeoutMillis?: (
mSec: number,
onSuccess: (recommendedTimeoutMillis: number) => void,
) => void;
}
export default (TurboModuleRegistry.get<Spec>('AccessibilityInfo'): ?Spec);

View File

@@ -0,0 +1,66 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getCurrentBoldTextState: (
onSuccess: (isBoldTextEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
+getCurrentGrayscaleState: (
onSuccess: (isGrayscaleEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
+getCurrentInvertColorsState: (
onSuccess: (isInvertColorsEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
+getCurrentReduceMotionState: (
onSuccess: (isReduceMotionEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
+getCurrentPrefersCrossFadeTransitionsState?: (
onSuccess: (prefersCrossFadeTransitions: boolean) => void,
onError: (error: Object) => void,
) => void;
+getCurrentReduceTransparencyState: (
onSuccess: (isReduceTransparencyEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
+getCurrentVoiceOverState: (
onSuccess: (isScreenReaderEnabled: boolean) => void,
onError: (error: Object) => void,
) => void;
+setAccessibilityContentSizeMultipliers: (JSMultipliers: {|
+extraSmall?: ?number,
+small?: ?number,
+medium?: ?number,
+large?: ?number,
+extraLarge?: ?number,
+extraExtraLarge?: ?number,
+extraExtraExtraLarge?: ?number,
+accessibilityMedium?: ?number,
+accessibilityLarge?: ?number,
+accessibilityExtraLarge?: ?number,
+accessibilityExtraExtraLarge?: ?number,
+accessibilityExtraExtraExtraLarge?: ?number,
|}) => void;
+setAccessibilityFocus: (reactTag: number) => void;
+announceForAccessibility: (announcement: string) => void;
+announceForAccessibilityWithOptions?: (
announcement: string,
options: {queue?: boolean},
) => void;
}
export default (TurboModuleRegistry.get<Spec>('AccessibilityManager'): ?Spec);

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
+showActionSheetWithOptions: (
options: {|
+title?: ?string,
+message?: ?string,
+options: ?Array<string>,
+destructiveButtonIndices?: ?Array<number>,
+cancelButtonIndex?: ?number,
+anchor?: ?number,
+tintColor?: ?number,
+cancelButtonTintColor?: ?number,
+userInterfaceStyle?: ?string,
+disabledButtonIndices?: Array<number>,
|},
callback: (buttonIndex: number) => void,
) => void;
+showShareActionSheetWithOptions: (
options: {|
+message?: ?string,
+url?: ?string,
+subject?: ?string,
+anchor?: ?number,
+tintColor?: ?number,
+cancelButtonTintColor?: ?number,
+excludedActivityTypes?: ?Array<string>,
+userInterfaceStyle?: ?string,
|},
failureCallback: (error: {|
+domain: string,
+code: string,
+userInfo?: ?Object,
+message: string,
|}) => void,
successCallback: (completed: boolean, activityType: ?string) => void,
) => void;
+dismissActionSheet?: () => void;
}
export default (TurboModuleRegistry.get<Spec>('ActionSheetManager'): ?Spec);

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type Args = {|
title?: string,
message?: string,
buttons?: Array<Object>, // TODO(T67565166): have a better type
type?: string,
defaultValue?: string,
cancelButtonKey?: string,
destructiveButtonKey?: string,
preferredButtonKey?: string,
keyboardType?: string,
userInterfaceStyle?: string,
|};
export interface Spec extends TurboModule {
+alertWithArgs: (
args: Args,
callback: (id: number, value: string) => void,
) => void;
}
export default (TurboModuleRegistry.get<Spec>('AlertManager'): ?Spec);

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import shouldUseTurboAnimatedModule from '../../../../Libraries/Animated/shouldUseTurboAnimatedModule';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
type EndResult = {finished: boolean, value?: number, ...};
type EndCallback = (result: EndResult) => void;
type SaveValueCallback = (value: number) => void;
export type EventMapping = {|
nativeEventPath: Array<string>,
animatedValueTag: ?number,
|};
// The config has different keys depending on the type of the Node
// TODO(T54896888): Make these types strict
export type AnimatedNodeConfig = Object;
export type AnimatingNodeConfig = Object;
export interface Spec extends TurboModule {
+startOperationBatch: () => void;
+finishOperationBatch: () => void;
+createAnimatedNode: (tag: number, config: AnimatedNodeConfig) => void;
+updateAnimatedNodeConfig?: (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;
+disconnectAnimatedNodes: (parentTag: number, childTag: number) => void;
+startAnimatingNode: (
animationId: number,
nodeTag: number,
config: AnimatingNodeConfig,
endCallback: EndCallback,
) => void;
+stopAnimation: (animationId: number) => void;
+setAnimatedNodeValue: (nodeTag: number, value: number) => void;
+setAnimatedNodeOffset: (nodeTag: number, offset: number) => void;
+flattenAnimatedNodeOffset: (nodeTag: number) => void;
+extractAnimatedNodeOffset: (nodeTag: number) => void;
+connectAnimatedNodeToView: (nodeTag: number, viewTag: number) => void;
+disconnectAnimatedNodeFromView: (nodeTag: number, viewTag: number) => void;
+restoreDefaultValues: (nodeTag: number) => void;
+dropAnimatedNode: (tag: number) => void;
+addAnimatedEventToView: (
viewTag: number,
eventName: string,
eventMapping: EventMapping,
) => void;
+removeAnimatedEventFromView: (
viewTag: number,
eventName: string,
animatedNodeTag: number,
) => void;
// Events
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
// All of the above in a batched mode
+queueAndExecuteBatchedOperations?: (operationsAndArgs: Array<any>) => void;
}
const NativeModule: ?Spec = !shouldUseTurboAnimatedModule()
? TurboModuleRegistry.get<Spec>('NativeAnimatedModule')
: null;
export default NativeModule;

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import shouldUseTurboAnimatedModule from '../../../../Libraries/Animated/shouldUseTurboAnimatedModule';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
type EndResult = {finished: boolean, value?: number, ...};
type EndCallback = (result: EndResult) => void;
type SaveValueCallback = (value: number) => void;
export type EventMapping = {|
nativeEventPath: Array<string>,
animatedValueTag: ?number,
|};
// The config has different keys depending on the type of the Node
// TODO(T54896888): Make these types strict
export type AnimatedNodeConfig = Object;
export type AnimatingNodeConfig = Object;
export interface Spec extends TurboModule {
+startOperationBatch: () => void;
+finishOperationBatch: () => void;
+createAnimatedNode: (tag: number, config: AnimatedNodeConfig) => void;
+updateAnimatedNodeConfig?: (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;
+disconnectAnimatedNodes: (parentTag: number, childTag: number) => void;
+startAnimatingNode: (
animationId: number,
nodeTag: number,
config: AnimatingNodeConfig,
endCallback: EndCallback,
) => void;
+stopAnimation: (animationId: number) => void;
+setAnimatedNodeValue: (nodeTag: number, value: number) => void;
+setAnimatedNodeOffset: (nodeTag: number, offset: number) => void;
+flattenAnimatedNodeOffset: (nodeTag: number) => void;
+extractAnimatedNodeOffset: (nodeTag: number) => void;
+connectAnimatedNodeToView: (nodeTag: number, viewTag: number) => void;
+disconnectAnimatedNodeFromView: (nodeTag: number, viewTag: number) => void;
+restoreDefaultValues: (nodeTag: number) => void;
+dropAnimatedNode: (tag: number) => void;
+addAnimatedEventToView: (
viewTag: number,
eventName: string,
eventMapping: EventMapping,
) => void;
+removeAnimatedEventFromView: (
viewTag: number,
eventName: string,
animatedNodeTag: number,
) => void;
// Events
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
// All of the above in a batched mode
+queueAndExecuteBatchedOperations?: (operationsAndArgs: Array<any>) => void;
}
const NativeModule: ?Spec = shouldUseTurboAnimatedModule()
? TurboModuleRegistry.get<Spec>('NativeAnimatedTurboModule')
: null;
export default NativeModule;

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+startRecordingFps: () => void;
+stopRecordingFps: (animationStopTimeMs: number) => void;
}
export default (TurboModuleRegistry.get<Spec>('AnimationsDebugModule'): ?Spec);

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type AppStateConstants = {|
initialAppState: string,
|};
export type AppState = {|app_state: string|};
export interface Spec extends TurboModule {
+getConstants: () => AppStateConstants;
+getCurrentAppState: (
success: (appState: AppState) => void,
error: (error: Object) => void,
) => void;
// Events
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('AppState'): Spec);

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type ColorSchemeName = 'light' | 'dark';
export type AppearancePreferences = {|
// TODO: (hramos) T52919652 Use ?ColorSchemeName once codegen supports union
// types.
/* 'light' | 'dark' */
colorScheme?: ?string,
|};
export interface Spec extends TurboModule {
// TODO: (hramos) T52919652 Use ?ColorSchemeName once codegen supports union
// types.
/* 'light' | 'dark' */
+getColorScheme: () => ?string;
+setColorScheme?: (colorScheme: string) => void;
// RCTEventEmitter
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.get<Spec>('Appearance'): ?Spec);

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|BLOB_URI_SCHEME: ?string, BLOB_URI_HOST: ?string|};
+addNetworkingHandler: () => void;
+addWebSocketHandler: (id: number) => void;
+removeWebSocketHandler: (id: number) => void;
+sendOverSocket: (blob: Object, socketID: number) => void;
+createFromParts: (parts: Array<Object>, withId: string) => void;
+release: (blobId: string) => void;
}
const NativeModule = TurboModuleRegistry.get<Spec>('BlobModule');
let constants = null;
let NativeBlobModule = null;
if (NativeModule != null) {
NativeBlobModule = {
getConstants(): {|BLOB_URI_SCHEME: ?string, BLOB_URI_HOST: ?string|} {
if (constants == null) {
constants = NativeModule.getConstants();
}
return constants;
},
addNetworkingHandler(): void {
NativeModule.addNetworkingHandler();
},
addWebSocketHandler(id: number): void {
NativeModule.addWebSocketHandler(id);
},
removeWebSocketHandler(id: number): void {
NativeModule.removeWebSocketHandler(id);
},
sendOverSocket(blob: Object, socketID: number): void {
NativeModule.sendOverSocket(blob, socketID);
},
createFromParts(parts: Array<Object>, withId: string): void {
NativeModule.createFromParts(parts, withId);
},
release(blobId: string): void {
NativeModule.release(blobId);
},
};
}
export default (NativeBlobModule: ?Spec);

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+startReportAProblemFlow: () => void;
+setExtraData: (extraData: Object, extraFiles: Object) => void;
}
export default (TurboModuleRegistry.get<Spec>('BugReporting'): ?Spec);

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
+getString: () => Promise<string>;
+setString: (content: string) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('Clipboard'): Spec);

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+showMessage: (
message: string,
withColor: ?number,
withBackgroundColor: ?number,
) => void;
+hide: () => void;
}
export default (TurboModuleRegistry.get<Spec>('DevLoadingView'): ?Spec);

View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+show: () => void;
+reload: () => void;
+debugRemotely: (enableDebug: boolean) => void;
+setProfilingEnabled: (enabled: boolean) => void;
+setHotLoadingEnabled: (enabled: boolean) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('DevMenu'): Spec);

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+reload: () => void;
+reloadWithReason?: (reason: string) => void;
+onFastRefresh?: () => void;
+setHotLoadingEnabled: (isHotLoadingEnabled: boolean) => void;
+setIsDebuggingRemotely: (isDebuggingRemotelyEnabled: boolean) => void;
+setProfilingEnabled: (isProfilingEnabled: boolean) => void;
+toggleElementInspector: () => void;
+addMenuItem: (title: string) => void;
// Events
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
// iOS only.
+setIsShakeToShowDevMenuEnabled: (enabled: boolean) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('DevSettings'): Spec);

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+setConsolePatchSettings: (newConsolePatchSettings: string) => void;
+getConsolePatchSettings: () => ?string;
+setProfilingSettings?: (newProfilingSettings: string) => void;
+getProfilingSettings?: () => ?string;
}
export default (TurboModuleRegistry.get<Spec>(
'DevToolsSettingsManager',
): ?Spec);

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+invokeDefaultBackPressHandler: () => void;
}
export default (TurboModuleRegistry.get<Spec>('DeviceEventManager'): ?Spec);

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type DisplayMetricsAndroid = {|
width: number,
height: number,
scale: number,
fontScale: number,
densityDpi: number,
|};
export type DisplayMetrics = {|
width: number,
height: number,
scale: number,
fontScale: number,
|};
export type DimensionsPayload = {|
window?: DisplayMetrics,
screen?: DisplayMetrics,
windowPhysicalPixels?: DisplayMetricsAndroid,
screenPhysicalPixels?: DisplayMetricsAndroid,
|};
export type DeviceInfoConstants = {|
+Dimensions: DimensionsPayload,
+isIPhoneX_deprecated?: boolean,
|};
export interface Spec extends TurboModule {
+getConstants: () => DeviceInfoConstants;
}
const NativeModule: Spec = TurboModuleRegistry.getEnforcing<Spec>('DeviceInfo');
let constants: ?DeviceInfoConstants = null;
const NativeDeviceInfo = {
getConstants(): DeviceInfoConstants {
if (constants == null) {
constants = NativeModule.getConstants();
}
return constants;
},
};
export default NativeDeviceInfo;

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
/* 'buttonClicked' | 'dismissed' */
type DialogAction = string;
/*
buttonPositive = -1,
buttonNegative = -2,
buttonNeutral = -3
*/
type DialogButtonKey = number;
export type DialogOptions = {|
title?: string,
message?: string,
buttonPositive?: string,
buttonNegative?: string,
buttonNeutral?: string,
items?: Array<string>,
cancelable?: boolean,
|};
export interface Spec extends TurboModule {
+getConstants: () => {|
+buttonClicked: DialogAction,
+dismissed: DialogAction,
+buttonPositive: DialogButtonKey,
+buttonNegative: DialogButtonKey,
+buttonNeutral: DialogButtonKey,
|};
+showAlert: (
config: DialogOptions,
onError: (error: string) => void,
onAction: (action: DialogAction, buttonKey?: DialogButtonKey) => void,
) => void;
}
export default (TurboModuleRegistry.get<Spec>('DialogManagerAndroid'): ?Spec);

View File

@@ -0,0 +1,103 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
const Platform = require('../../../../Libraries/Utilities/Platform');
export type StackFrame = {|
column: ?number,
file: ?string,
lineNumber: ?number,
methodName: string,
collapse?: boolean,
|};
export type ExceptionData = {
message: string,
originalMessage: ?string,
name: ?string,
componentStack: ?string,
stack: Array<StackFrame>,
id: number,
isFatal: boolean,
// flowlint-next-line unclear-type:off
extraData?: Object,
...
};
export interface Spec extends TurboModule {
// Deprecated: Use `reportException`
+reportFatalException: (
message: string,
stack: Array<StackFrame>,
exceptionId: number,
) => void;
// Deprecated: Use `reportException`
+reportSoftException: (
message: string,
stack: Array<StackFrame>,
exceptionId: number,
) => void;
+reportException?: (data: ExceptionData) => void;
+updateExceptionMessage: (
message: string,
stack: Array<StackFrame>,
exceptionId: number,
) => void;
// TODO(T53311281): This is a noop on iOS now. Implement it.
+dismissRedbox?: () => void;
}
const NativeModule =
TurboModuleRegistry.getEnforcing<Spec>('ExceptionsManager');
const ExceptionsManager = {
reportFatalException(
message: string,
stack: Array<StackFrame>,
exceptionId: number,
) {
NativeModule.reportFatalException(message, stack, exceptionId);
},
reportSoftException(
message: string,
stack: Array<StackFrame>,
exceptionId: number,
) {
NativeModule.reportSoftException(message, stack, exceptionId);
},
updateExceptionMessage(
message: string,
stack: Array<StackFrame>,
exceptionId: number,
) {
NativeModule.updateExceptionMessage(message, stack, exceptionId);
},
dismissRedbox(): void {
if (Platform.OS !== 'ios' && NativeModule.dismissRedbox) {
// TODO(T53311281): This is a noop on iOS now. Implement it.
NativeModule.dismissRedbox();
}
},
reportException(data: ExceptionData): void {
if (NativeModule.reportException) {
NativeModule.reportException(data);
return;
}
if (data.isFatal) {
ExceptionsManager.reportFatalException(data.message, data.stack, data.id);
} else {
ExceptionsManager.reportSoftException(data.message, data.stack, data.id);
}
},
};
export default ExceptionsManager;

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+readAsDataURL: (data: Object) => Promise<string>;
+readAsText: (data: Object, encoding: string) => Promise<string>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'FileReaderModule',
): Spec);

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+setGlobalOptions: (options: {|+debug?: ?boolean|}) => void;
+setContext: (context: string) => void;
+beginScroll: () => void;
+endScroll: () => void;
}
export default (TurboModuleRegistry.get<Spec>('FrameRateLogger'): ?Spec);

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+notifyTaskFinished: (taskId: number) => void;
+notifyTaskRetry: (taskId: number) => Promise<boolean>;
}
export default (TurboModuleRegistry.get<Spec>('HeadlessJsTaskSupport'): ?Spec);

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type I18nManagerConstants = {|
doLeftAndRightSwapInRTL: boolean,
isRTL: boolean,
localeIdentifier?: ?string,
|};
export interface Spec extends TurboModule {
+getConstants: () => I18nManagerConstants;
allowRTL: (allowRTL: boolean) => void;
forceRTL: (forceRTL: boolean) => void;
swapLeftAndRightInRTL: (flipStyles: boolean) => void;
}
export default (TurboModuleRegistry.get<Spec>('I18nManager'): ?Spec);

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
type Options = {|
+offset: {|
+x: number,
+y: number,
|},
+size: {|
+width: number,
+height: number,
|},
+displaySize?: ?{|
+width: number,
+height: number,
|},
/**
* Enum with potential values:
* - cover
* - contain
* - stretch
* - center
* - repeat
*/
+resizeMode?: ?string,
+allowExternalStorage?: boolean,
|};
export interface Spec extends TurboModule {
+getConstants: () => {||};
+cropImage: (
uri: string,
cropData: Options,
successCallback: (uri: string) => void,
errorCallback: (error: string) => void,
) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'ImageEditingManager',
): Spec);

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type ImageSize = {
width: number,
height: number,
...
};
export interface Spec extends TurboModule {
+abortRequest: (requestId: number) => void;
+getConstants: () => {||};
+getSize: (uri: string) => Promise<ImageSize>;
+getSizeWithHeaders: (uri: string, headers: Object) => Promise<ImageSize>;
+prefetchImage: (uri: string, requestId: number) => Promise<boolean>;
+queryCache: (uris: Array<string>) => Promise<Object>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('ImageLoader'): Spec);

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {RootTag} from '../../../../Libraries/TurboModule/RCTExport';
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
// Return [width, height] of image uri
+getSize: (uri: string) => Promise<$ReadOnlyArray<number>>;
+getSizeWithHeaders: (
uri: string,
headers: Object,
) => Promise<{
width: number,
height: number,
...
}>;
+prefetchImage: (uri: string) => Promise<boolean>;
+prefetchImageWithMetadata?: (
uri: string,
queryRootName: string,
rootTag: RootTag,
) => Promise<boolean>;
+queryCache: (uris: Array<string>) => Promise<Object>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('ImageLoader'): Spec);

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
+getBase64ForTag: (
uri: string,
successCallback: (base64ImageData: string) => void,
errorCallback: (error: string) => void,
) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'ImageStoreManager',
): Spec);

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
+getBase64ForTag: (
uri: string,
successCallback: (base64ImageData: string) => void,
errorCallback: (error: {|message: string|}) => void,
) => void;
+hasImageForTag: (uri: string, callback: (hasImage: boolean) => void) => void;
+removeImageForTag: (uri: string) => void;
+addImageFromBase64: (
base64ImageData: string,
successCallback: (uri: string) => void,
errorCallback: (error: {|message: string|}) => void,
) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'ImageStoreManager',
): Spec);

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getInitialURL: () => Promise<string>;
+canOpenURL: (url: string) => Promise<boolean>;
+openURL: (url: string) => Promise<void>;
+openSettings: () => Promise<void>;
+sendIntent: (
action: string,
extras: ?Array<{
key: string,
value: string | number | boolean, // TODO(T67672788): Union types are not type safe
...
}>,
) => Promise<void>;
}
export default (TurboModuleRegistry.get<Spec>('IntentAndroid'): ?Spec);

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type NativeIntersectionObserverEntry = {
intersectionObserverId: number,
targetInstanceHandle: mixed,
targetRect: $ReadOnlyArray<number>, // It's actually a tuple with x, y, width and height
rootRect: $ReadOnlyArray<number>, // It's actually a tuple with x, y, width and height
intersectionRect: ?$ReadOnlyArray<number>, // It's actually a tuple with x, y, width and height
isIntersectingAboveThresholds: boolean,
time: number,
};
export type NativeIntersectionObserverObserveOptions = {
intersectionObserverId: number,
targetShadowNode: mixed,
thresholds: $ReadOnlyArray<number>,
};
export interface Spec extends TurboModule {
+observe: (options: NativeIntersectionObserverObserveOptions) => void;
+unobserve: (intersectionObserverId: number, targetShadowNode: mixed) => void;
+connect: (notifyIntersectionObserversCallback: () => void) => void;
+disconnect: () => void;
+takeRecords: () => $ReadOnlyArray<NativeIntersectionObserverEntry>;
}
export default (TurboModuleRegistry.get<Spec>(
'NativeIntersectionObserverCxx',
): ?Spec);

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+captureComplete: (path: string, error: ?string) => void;
}
export default (TurboModuleRegistry.get<Spec>('JSCHeapCapture'): ?Spec);

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+operationComplete: (token: number, result: ?string, error: ?string) => void;
}
export default (TurboModuleRegistry.get<Spec>('JSCSamplingProfiler'): ?Spec);

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.get<Spec>('KeyboardObserver'): ?Spec);

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
// Common interface
+getInitialURL: () => Promise<string>;
+canOpenURL: (url: string) => Promise<boolean>;
+openURL: (url: string) => Promise<void>;
+openSettings: () => Promise<void>;
// Events
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.get<Spec>('LinkingManager'): ?Spec);

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+show: () => void;
+hide: () => void;
}
export default (TurboModuleRegistry.get<Spec>('LogBox'): ?Spec);

View File

@@ -0,0 +1,21 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
// RCTEventEmitter
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.get<Spec>('ModalManager'): ?Spec);

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type MutationObserverId = number;
// These types are not supported by the codegen.
type ShadowNode = mixed;
type InstanceHandle = mixed;
type ReactNativeElement = mixed;
type ReadOnlyNode = mixed;
export type NativeMutationRecord = {
mutationObserverId: MutationObserverId,
target: ReactNativeElement,
addedNodes: $ReadOnlyArray<ReadOnlyNode>,
removedNodes: $ReadOnlyArray<ReadOnlyNode>,
...
};
export type NativeMutationObserverObserveOptions = {
mutationObserverId: number,
targetShadowNode: ShadowNode,
subtree: boolean,
};
export interface Spec extends TurboModule {
+observe: (options: NativeMutationObserverObserveOptions) => void;
+unobserve: (
mutationObserverId: number,
targetShadowNode: ShadowNode,
) => void;
+connect: (
notifyMutationObservers: () => void,
// We need this to retain the public instance before React removes the
// reference to it (which happen in mutations that remove nodes, or when
// nodes are removed between the change and the callback is executed in JS).
getPublicInstanceFromInstanceHandle: (
instanceHandle: InstanceHandle,
) => ReadOnlyNode,
) => void;
+disconnect: () => void;
+takeRecords: () => $ReadOnlyArray<NativeMutationRecord>;
}
export default (TurboModuleRegistry.get<Spec>(
'NativeMutationObserverCxx',
): ?Spec);

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
type Header = [string, string];
export interface Spec extends TurboModule {
+sendRequest: (
method: string,
url: string,
requestId: number,
headers: Array<Header>,
data: Object,
responseType: string,
useIncrementalUpdates: boolean,
timeout: number,
withCredentials: boolean,
) => void;
+abortRequest: (requestId: number) => void;
+clearCookies: (callback: (result: boolean) => void) => void;
// RCTEventEmitter
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('Networking'): Spec);

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+sendRequest: (
query: {|
method: string,
url: string,
data: Object,
headers: Object,
responseType: string,
incrementalUpdates: boolean,
timeout: number,
withCredentials: boolean,
|},
callback: (requestId: number) => void,
) => void;
+abortRequest: (requestId: number) => void;
+clearCookies: (callback: (result: boolean) => void) => void;
// RCTEventEmitter
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('Networking'): Spec);

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
// TODO: Use proper enum types.
export type PermissionStatus = string;
export type PermissionType = string;
/*
export type PermissionStatus = 'granted' | 'denied' | 'never_ask_again';
export type PermissionType =
| 'android.permission.READ_CALENDAR'
| 'android.permission.WRITE_CALENDAR'
| 'android.permission.CAMERA'
| 'android.permission.READ_CONTACTS'
| 'android.permission.WRITE_CONTACTS'
| 'android.permission.GET_ACCOUNTS'
| 'android.permission.ACCESS_BACKGROUND_LOCATION'
| 'android.permission.ACCESS_FINE_LOCATION'
| 'android.permission.ACCESS_COARSE_LOCATION'
| 'android.permission.RECORD_AUDIO'
| 'android.permission.READ_PHONE_STATE'
| 'android.permission.CALL_PHONE'
| 'android.permission.READ_CALL_LOG'
| 'android.permission.WRITE_CALL_LOG'
| 'com.android.voicemail.permission.ADD_VOICEMAIL'
| 'com.android.voicemail.permission.READ_VOICEMAIL'
| 'com.android.voicemail.permission.WRITE_VOICEMAIL'
| 'android.permission.USE_SIP'
| 'android.permission.PROCESS_OUTGOING_CALLS'
| 'android.permission.BODY_SENSORS'
| 'android.permission.BODY_SENSORS_BACKGROUND'
| 'android.permission.SEND_SMS'
| 'android.permission.RECEIVE_SMS'
| 'android.permission.READ_SMS'
| 'android.permission.RECEIVE_WAP_PUSH'
| 'android.permission.RECEIVE_MMS'
| 'android.permission.READ_EXTERNAL_STORAGE'
| 'android.permission.READ_MEDIA_IMAGES',
| 'android.permission.READ_MEDIA_VIDEO',
| 'android.permission.READ_MEDIA_AUDIO',
| 'android.permission.READ_MEDIA_VISUAL_USER_SELECTED'
| 'android.permission.WRITE_EXTERNAL_STORAGE'
| 'android.permission.BLUETOOTH_CONNECT'
| 'android.permission.BLUETOOTH_SCAN'
| 'android.permission.BLUETOOTH_ADVERTISE'
| 'android.permission.ACCESS_MEDIA_LOCATION'
| 'android.permission.ACCEPT_HANDOVER'
| 'android.permission.ACTIVITY_RECOGNITION'
| 'android.permission.ANSWER_PHONE_CALLS'
| 'android.permission.READ_PHONE_NUMBERS'
| 'android.permission.UWB_RANGING'
| 'android.permission.POST_NOTIFICATIONS'
| 'android.permission.NEARBY_WIFI_DEVICES';
*/
export interface Spec extends TurboModule {
+checkPermission: (permission: PermissionType) => Promise<boolean>;
+requestPermission: (permission: PermissionType) => Promise<PermissionStatus>;
+shouldShowRequestPermissionRationale: (
permission: string,
) => Promise<boolean>;
+requestMultiplePermissions: (
permissions: Array<PermissionType>,
) => Promise<{[permission: PermissionType]: PermissionStatus, ...}>;
}
export default (TurboModuleRegistry.get<Spec>('PermissionsAndroid'): ?Spec);

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type ReactNativeVersionAndroid = {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|};
export type PlatformConstantsAndroid = {|
isTesting: boolean,
isDisableAnimations?: boolean,
reactNativeVersion: ReactNativeVersionAndroid,
Version: number,
Release: string,
Serial: string,
Fingerprint: string,
Model: string,
ServerHost?: string,
uiMode: string,
Brand: string,
Manufacturer: string,
|};
export interface Spec extends TurboModule {
+getConstants: () => PlatformConstantsAndroid;
+getAndroidID: () => string;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'PlatformConstants',
): Spec);

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type PlatformConstantsIOS = {|
isTesting: boolean,
isDisableAnimations?: boolean,
reactNativeVersion: {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|},
forceTouchAvailable: boolean,
osVersion: string,
systemName: string,
interfaceIdiom: string,
isMacCatalyst?: boolean,
|};
export interface Spec extends TurboModule {
+getConstants: () => PlatformConstantsIOS;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'PlatformConstants',
): Spec);

View File

@@ -0,0 +1,107 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
type Permissions = {|
alert: boolean,
badge: boolean,
sound: boolean,
|};
type Notification = {|
+alertTitle?: ?string,
+alertBody?: ?string,
+userInfo?: ?Object,
/**
* Identifier for the notification category. See the [Apple documentation](https://developer.apple.com/documentation/usernotifications/declaring_your_actionable_notification_types)
* for more details.
*/
+category?: ?string,
/**
* Actual type: string | number
*
* Schedule notifications using EITHER `fireDate` or `fireIntervalSeconds`.
* If both are specified, `fireDate` takes precedence.
* If you use `presentLocalNotification`, both will be ignored
* and the notification will be shown immediately.
*/
+fireDate?: ?number,
/**
* Seconds from now to display the notification.
*
* Schedule notifications using EITHER `fireDate` or `fireIntervalSeconds`.
* If both are specified, `fireDate` takes precedence.
* If you use `presentLocalNotification`, both will be ignored
* and the notification will be shown immediately.
*/
+fireIntervalSeconds?: ?number,
/** Badge count to display on the app icon. */
+applicationIconBadgeNumber?: ?number,
/** Whether to silence the notification sound. */
+isSilent?: ?boolean,
/**
* Custom notification sound. Can only be set when creating notifications.
* This will be null for notifications retrieved via
* getScheduledLocalNotifications or getDeliveredNotifications.
*/
+soundName?: ?string,
/** DEPRECATED. This was used for iOS's legacy UILocalNotification. */
+alertAction?: ?string,
/** DEPRECATED. Use `fireDate` or `fireIntervalSeconds` instead. */
+repeatInterval?: ?string,
|};
export interface Spec extends TurboModule {
+getConstants: () => {||};
+onFinishRemoteNotification: (
notificationId: string,
/**
* Type:
* 'UIBackgroundFetchResultNewData' |
* 'UIBackgroundFetchResultNoData' |
* 'UIBackgroundFetchResultFailed'
*/
fetchResult: string,
) => void;
+setApplicationIconBadgeNumber: (num: number) => void;
+getApplicationIconBadgeNumber: (callback: (num: number) => void) => void;
+requestPermissions: (permission: {|
+alert: boolean,
+badge: boolean,
+sound: boolean,
|}) => Promise<Permissions>;
+abandonPermissions: () => void;
+checkPermissions: (callback: (permissions: Permissions) => void) => void;
+presentLocalNotification: (notification: Notification) => void;
+scheduleLocalNotification: (notification: Notification) => void;
+cancelAllLocalNotifications: () => void;
+cancelLocalNotifications: (userInfo: Object) => void;
+getInitialNotification: () => Promise<?Notification>;
+getScheduledLocalNotifications: (
callback: (notification: Notification) => void,
) => void;
+removeAllDeliveredNotifications: () => void;
+removeDeliveredNotifications: (identifiers: Array<string>) => void;
+getDeliveredNotifications: (
callback: (notification: Array<Notification>) => void,
) => void;
+getAuthorizationStatus: (
callback: (authorizationStatus: number) => void,
) => void;
+addListener: (eventType: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.get<Spec>(
'PushNotificationManager',
): ?Spec);

View File

@@ -0,0 +1,20 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+setExtraData: (extraData: Object, forIdentifier: string) => void;
+dismiss: () => void;
}
export default (TurboModuleRegistry.get<Spec>('RedBox'): ?Spec);

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {
RootTag,
TurboModule,
} from '../../../../Libraries/TurboModule/RCTExport';
import type {UnsafeObject} from '../../../../Libraries/Types/CodegenTypes';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export enum EnumInt {
A = 23,
B = 42,
}
export interface Spec extends TurboModule {
// Exported methods.
+getConstants: () => {|
const1: boolean,
const2: number,
const3: string,
|};
+voidFunc: () => void;
+getBool: (arg: boolean) => boolean;
+getEnum?: (arg: EnumInt) => EnumInt;
+getNumber: (arg: number) => number;
+getString: (arg: string) => string;
+getArray: (arg: Array<any>) => Array<any>;
+getObject: (arg: Object) => Object;
+getUnsafeObject: (arg: UnsafeObject) => UnsafeObject;
+getRootTag: (arg: RootTag) => RootTag;
+getValue: (x: number, y: string, z: Object) => Object;
+getValueWithCallback: (callback: (value: string) => void) => void;
+getValueWithPromise: (error: boolean) => Promise<string>;
+voidFuncThrows?: () => void;
+getObjectThrows?: (arg: Object) => Object;
+promiseThrows?: () => Promise<void>;
+voidFuncAssert?: () => void;
+getObjectAssert?: (arg: Object) => Object;
+promiseAssert?: () => Promise<void>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'SampleTurboModule',
): Spec);

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+fetchSegment: (
segmentId: number,
options: Object, // flowlint-line unclear-type: off
callback: (error: ?Object) => void, // flowlint-line unclear-type: off
) => void;
+getSegment?: (
segmentId: number,
options: Object, // flowlint-line unclear-type: off
callback: (error: ?Object, path: ?string) => void, // flowlint-line unclear-type: off
) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('SegmentFetcher'): Spec);

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|
settings: Object,
|};
+setValues: (values: Object) => void;
+deleteValues: (values: Array<string>) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'SettingsManager',
): Spec);

View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
+share: (
content: {|title?: string, message?: string|},
dialogTitle?: string,
) => Promise<{|action: string|}>;
}
export default (TurboModuleRegistry.get<Spec>('ShareModule'): ?Spec);

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
/**
* Native Module used for playing sounds in native platform.
*/
export interface Spec extends TurboModule {
+playTouchSound: () => void;
}
export default (TurboModuleRegistry.get<Spec>('SoundManager'): ?Spec);

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type SourceCodeConstants = {|
scriptURL: string,
|};
export interface Spec extends TurboModule {
+getConstants: () => SourceCodeConstants;
}
const NativeModule = TurboModuleRegistry.getEnforcing<Spec>('SourceCode');
let constants = null;
const NativeSourceCode = {
getConstants(): SourceCodeConstants {
if (constants == null) {
constants = NativeModule.getConstants();
}
return constants;
},
};
export default NativeSourceCode;

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|
+HEIGHT: number,
+DEFAULT_BACKGROUND_COLOR: number,
|};
+setColor: (color: number, animated: boolean) => void;
+setTranslucent: (translucent: boolean) => void;
/**
* - statusBarStyles can be:
* - 'default'
* - 'dark-content'
*/
+setStyle: (statusBarStyle?: ?string) => void;
+setHidden: (hidden: boolean) => void;
}
const NativeModule = TurboModuleRegistry.getEnforcing<Spec>('StatusBarManager');
let constants = null;
const NativeStatusBarManager = {
getConstants(): {|
+HEIGHT: number,
+DEFAULT_BACKGROUND_COLOR?: number,
|} {
if (constants == null) {
constants = NativeModule.getConstants();
}
return constants;
},
setColor(color: number, animated: boolean): void {
NativeModule.setColor(color, animated);
},
setTranslucent(translucent: boolean): void {
NativeModule.setTranslucent(translucent);
},
/**
* - statusBarStyles can be:
* - 'default'
* - 'dark-content'
*/
setStyle(statusBarStyle?: ?string): void {
NativeModule.setStyle(statusBarStyle);
},
setHidden(hidden: boolean): void {
NativeModule.setHidden(hidden);
},
};
export default NativeStatusBarManager;

View File

@@ -0,0 +1,89 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|
+HEIGHT: number,
+DEFAULT_BACKGROUND_COLOR?: number,
|};
// TODO(T47754272) Can we remove this method?
+getHeight: (callback: (result: {|height: number|}) => void) => void;
+setNetworkActivityIndicatorVisible: (visible: boolean) => void;
+addListener: (eventType: string) => void;
+removeListeners: (count: number) => void;
/**
* - statusBarStyles can be:
* - 'default'
* - 'dark-content'
* - 'light-content'
*/
+setStyle: (statusBarStyle?: ?string, animated: boolean) => void;
/**
* - withAnimation can be: 'none' | 'fade' | 'slide'
*/
+setHidden: (hidden: boolean, withAnimation: string) => void;
}
const NativeModule = TurboModuleRegistry.getEnforcing<Spec>('StatusBarManager');
let constants = null;
const NativeStatusBarManager = {
getConstants(): {|
+HEIGHT: number,
+DEFAULT_BACKGROUND_COLOR?: number,
|} {
if (constants == null) {
constants = NativeModule.getConstants();
}
return constants;
},
// TODO(T47754272) Can we remove this method?
getHeight(callback: (result: {|height: number|}) => void): void {
NativeModule.getHeight(callback);
},
setNetworkActivityIndicatorVisible(visible: boolean): void {
NativeModule.setNetworkActivityIndicatorVisible(visible);
},
addListener(eventType: string): void {
NativeModule.addListener(eventType);
},
removeListeners(count: number): void {
NativeModule.removeListeners(count);
},
/**
* - statusBarStyles can be:
* - 'default'
* - 'dark-content'
* - 'light-content'
*/
setStyle(statusBarStyle?: ?string, animated: boolean): void {
NativeModule.setStyle(statusBarStyle, animated);
},
/**
* - withAnimation can be: 'none' | 'fade' | 'slide'
*/
setHidden(hidden: boolean, withAnimation: string): void {
NativeModule.setHidden(hidden, withAnimation);
},
};
export default NativeStatusBarManager;

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+createTimer: (
callbackID: number,
duration: number,
jsSchedulingTime: number,
repeats: boolean,
) => void;
+deleteTimer: (timerID: number) => void;
+setSendIdleEvents: (sendIdleEvents: boolean) => void;
}
export default (TurboModuleRegistry.get<Spec>('Timing'): ?Spec);

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|
SHORT: number,
LONG: number,
TOP: number,
BOTTOM: number,
CENTER: number,
|};
+show: (message: string, duration: number) => void;
+showWithGravity: (
message: string,
duration: number,
gravity: number,
) => void;
+showWithGravityAndOffset: (
message: string,
duration: number,
gravity: number,
xOffset: number,
yOffset: number,
) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('ToastAndroid'): Spec);

View File

@@ -0,0 +1,118 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {RootTag} from '../../../../Libraries/TurboModule/RCTExport';
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => Object;
+createView: (
reactTag: number,
viewName: string,
rootTag: RootTag,
props: Object,
) => void;
+updateView: (reactTag: number, viewName: string, props: Object) => void;
+findSubviewIn: (
reactTag: number,
point: Array<number>,
callback: (
nativeViewTag: number,
left: number,
top: number,
width: number,
height: number,
) => void,
) => void;
+dispatchViewManagerCommand: (
reactTag: number,
commandID: number, // number || string
commandArgs: ?Array<any>,
) => void;
+measure: (
reactTag: number,
callback: (
left: number,
top: number,
width: number,
height: number,
pageX: number,
pageY: number,
) => void,
) => void;
+measureInWindow: (
reactTag: number,
callback: (x: number, y: number, width: number, height: number) => void,
) => void;
+viewIsDescendantOf: (
reactTag: number,
ancestorReactTag: number,
callback: (result: Array<boolean>) => void,
) => void;
+measureLayout: (
reactTag: number,
ancestorReactTag: number,
errorCallback: (error: Object) => void,
callback: (
left: number,
top: number,
width: number,
height: number,
) => void,
) => void;
+measureLayoutRelativeToParent: (
reactTag: number,
errorCallback: (error: Object) => void,
callback: (
left: number,
top: number,
width: number,
height: number,
) => void,
) => void;
+setJSResponder: (reactTag: number, blockNativeResponder: boolean) => void;
+clearJSResponder: () => void;
+configureNextLayoutAnimation: (
config: Object,
callback: () => void, // check what is returned here
errorCallback: (error: Object) => void,
) => void;
+setChildren: (containerTag: number, reactTags: Array<number>) => void;
+manageChildren: (
containerTag: number,
moveFromIndices: Array<number>,
moveToIndices: Array<number>,
addChildReactTags: Array<number>,
addAtIndices: Array<number>,
removeAtIndices: Array<number>,
) => void;
// Android only
+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;
// ios only
+lazilyLoadView?: (name: string) => Object; // revisit return
+focus?: (reactTag: number) => void;
+blur?: (reactTag: number) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('UIManager'): Spec);

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
+vibrate: (pattern: number) => void;
// Android only
+vibrateByPattern: (pattern: Array<number>, repeat: number) => void;
+cancel: () => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>('Vibration'): Spec);

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+connect: (
url: string,
protocols: ?Array<string>,
options: {|headers?: Object|},
socketID: number,
) => void;
+send: (message: string, forSocketID: number) => void;
+sendBinary: (base64String: string, forSocketID: number) => void;
+ping: (socketID: number) => void;
+close: (code: number, reason: string, socketID: number) => void;
// RCTEventEmitter
+addListener: (eventName: string) => void;
+removeListeners: (count: number) => void;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'WebSocketModule',
): Spec);

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
/**
* The JSDoc comments in this file have been extracted from [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect).
* Content by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect/contributors.txt),
* licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
*/
import DOMRectReadOnly, {type DOMRectLike} from './DOMRectReadOnly';
// flowlint unsafe-getters-setters:off
/**
* A `DOMRect` describes the size and position of a rectangle.
* The type of box represented by the `DOMRect` is specified by the method or property that returned it.
*
* This is a (mostly) spec-compliant version of `DOMRect` (https://developer.mozilla.org/en-US/docs/Web/API/DOMRect).
*/
export default class DOMRect extends DOMRectReadOnly {
/**
* The x coordinate of the `DOMRect`'s origin.
*/
get x(): number {
return this.__getInternalX();
}
set x(x: ?number) {
this.__setInternalX(x);
}
/**
* The y coordinate of the `DOMRect`'s origin.
*/
get y(): number {
return this.__getInternalY();
}
set y(y: ?number) {
this.__setInternalY(y);
}
/**
* The width of the `DOMRect`.
*/
get width(): number {
return this.__getInternalWidth();
}
set width(width: ?number) {
this.__setInternalWidth(width);
}
/**
* The height of the `DOMRect`.
*/
get height(): number {
return this.__getInternalHeight();
}
set height(height: ?number) {
this.__setInternalHeight(height);
}
/**
* Creates a new `DOMRect` object with a given location and dimensions.
*/
static fromRect(rect?: ?DOMRectLike): DOMRect {
if (!rect) {
return new DOMRect();
}
return new DOMRect(rect.x, rect.y, rect.width, rect.height);
}
}

View File

@@ -0,0 +1,188 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
/**
* The JSDoc comments in this file have been extracted from [DOMRectReadOnly](https://developer.mozilla.org/en-US/docs/Web/API/DOMRectReadOnly).
* Content by [Mozilla Contributors](https://developer.mozilla.org/en-US/docs/Web/API/DOMRectReadOnly/contributors.txt),
* licensed under [CC-BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5/).
*/
// flowlint sketchy-null:off, unsafe-getters-setters:off
export interface DOMRectLike {
x?: ?number;
y?: ?number;
width?: ?number;
height?: ?number;
}
function castToNumber(value: mixed): number {
return value ? Number(value) : 0;
}
/**
* The `DOMRectReadOnly` interface specifies the standard properties used by `DOMRect` to define a rectangle whose properties are immutable.
*
* This is a (mostly) spec-compliant version of `DOMRectReadOnly` (https://developer.mozilla.org/en-US/docs/Web/API/DOMRectReadOnly).
*/
export default class DOMRectReadOnly {
_x: number;
_y: number;
_width: number;
_height: number;
constructor(x: ?number, y: ?number, width: ?number, height: ?number) {
this.__setInternalX(x);
this.__setInternalY(y);
this.__setInternalWidth(width);
this.__setInternalHeight(height);
}
/**
* The x coordinate of the `DOMRectReadOnly`'s origin.
*/
get x(): number {
return this._x;
}
/**
* The y coordinate of the `DOMRectReadOnly`'s origin.
*/
get y(): number {
return this._y;
}
/**
* The width of the `DOMRectReadOnly`.
*/
get width(): number {
return this._width;
}
/**
* The height of the `DOMRectReadOnly`.
*/
get height(): number {
return this._height;
}
/**
* Returns the top coordinate value of the `DOMRect` (has the same value as `y`, or `y + height` if `height` is negative).
*/
get top(): number {
const height = this._height;
const y = this._y;
if (height < 0) {
return y + height;
}
return y;
}
/**
* Returns the right coordinate value of the `DOMRect` (has the same value as ``x + width`, or `x` if `width` is negative).
*/
get right(): number {
const width = this._width;
const x = this._x;
if (width < 0) {
return x;
}
return x + width;
}
/**
* Returns the bottom coordinate value of the `DOMRect` (has the same value as `y + height`, or `y` if `height` is negative).
*/
get bottom(): number {
const height = this._height;
const y = this._y;
if (height < 0) {
return y;
}
return y + height;
}
/**
* Returns the left coordinate value of the `DOMRect` (has the same value as `x`, or `x + width` if `width` is negative).
*/
get left(): number {
const width = this._width;
const x = this._x;
if (width < 0) {
return x + width;
}
return x;
}
toJSON(): {
x: number,
y: number,
width: number,
height: number,
top: number,
left: number,
bottom: number,
right: number,
} {
const {x, y, width, height, top, left, bottom, right} = this;
return {x, y, width, height, top, left, bottom, right};
}
/**
* Creates a new `DOMRectReadOnly` object with a given location and dimensions.
*/
static fromRect(rect?: ?DOMRectLike): DOMRectReadOnly {
if (!rect) {
return new DOMRectReadOnly();
}
return new DOMRectReadOnly(rect.x, rect.y, rect.width, rect.height);
}
__getInternalX(): number {
return this._x;
}
__getInternalY(): number {
return this._y;
}
__getInternalWidth(): number {
return this._width;
}
__getInternalHeight(): number {
return this._height;
}
__setInternalX(x: ?number) {
this._x = castToNumber(x);
}
__setInternalY(y: ?number) {
this._y = castToNumber(y);
}
__setInternalWidth(width: ?number) {
this._width = castToNumber(width);
}
__setInternalHeight(height: ?number) {
this._height = castToNumber(height);
}
}

View File

@@ -0,0 +1,192 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
// flowlint unsafe-getters-setters:off
import type {
HostComponent,
INativeMethods,
InternalInstanceHandle,
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
ViewConfig,
} from '../../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {ElementRef} from 'react';
import TextInputState from '../../../../../Libraries/Components/TextInput/TextInputState';
import {getFabricUIManager} from '../../../../../Libraries/ReactNative/FabricUIManager';
import {create as createAttributePayload} from '../../../../../Libraries/ReactNative/ReactFabricPublicInstance/ReactNativeAttributePayload';
import warnForStyleProps from '../../../../../Libraries/ReactNative/ReactFabricPublicInstance/warnForStyleProps';
import ReadOnlyElement, {getBoundingClientRect} from './ReadOnlyElement';
import ReadOnlyNode from './ReadOnlyNode';
import {
getPublicInstanceFromInternalInstanceHandle,
getShadowNode,
} from './ReadOnlyNode';
import nullthrows from 'nullthrows';
const noop = () => {};
export default class ReactNativeElement
extends ReadOnlyElement
implements INativeMethods
{
// These need to be accessible from `ReactFabricPublicInstanceUtils`.
__nativeTag: number;
__internalInstanceHandle: InternalInstanceHandle;
_viewConfig: ViewConfig;
constructor(
tag: number,
viewConfig: ViewConfig,
internalInstanceHandle: InternalInstanceHandle,
) {
super(internalInstanceHandle);
this.__nativeTag = tag;
this.__internalInstanceHandle = internalInstanceHandle;
this._viewConfig = viewConfig;
}
get offsetHeight(): number {
return Math.round(
getBoundingClientRect(this, {includeTransform: false}).height,
);
}
get offsetLeft(): number {
const node = getShadowNode(this);
if (node != null) {
const offset = nullthrows(getFabricUIManager()).getOffset(node);
if (offset != null) {
return Math.round(offset[2]);
}
}
return 0;
}
get offsetParent(): ReadOnlyElement | null {
const node = getShadowNode(this);
if (node != null) {
const offset = nullthrows(getFabricUIManager()).getOffset(node);
// For children of the root node we currently return offset data
// but a `null` parent because the root node is not accessible
// in JavaScript yet.
if (offset != null && offset[0] != null) {
const offsetParentInstanceHandle = offset[0];
const offsetParent = getPublicInstanceFromInternalInstanceHandle(
offsetParentInstanceHandle,
);
// $FlowExpectedError[incompatible-type] The value returned by `getOffset` is always an instance handle for `ReadOnlyElement`.
const offsetParentElement: ReadOnlyElement | null = offsetParent;
return offsetParentElement;
}
}
return null;
}
get offsetTop(): number {
const node = getShadowNode(this);
if (node != null) {
const offset = nullthrows(getFabricUIManager()).getOffset(node);
if (offset != null) {
return Math.round(offset[1]);
}
}
return 0;
}
get offsetWidth(): number {
return Math.round(
getBoundingClientRect(this, {includeTransform: false}).width,
);
}
/**
* React Native compatibility methods
*/
blur(): void {
// $FlowFixMe[incompatible-exact] Migrate all usages of `NativeMethods` to an interface to fix this.
TextInputState.blurTextInput(this);
}
focus() {
// $FlowFixMe[incompatible-exact] Migrate all usages of `NativeMethods` to an interface to fix this.
TextInputState.focusTextInput(this);
}
measure(callback: MeasureOnSuccessCallback) {
const node = getShadowNode(this);
if (node != null) {
nullthrows(getFabricUIManager()).measure(node, callback);
}
}
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
const node = getShadowNode(this);
if (node != null) {
nullthrows(getFabricUIManager()).measureInWindow(node, callback);
}
}
measureLayout(
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void /* currently unused */,
) {
if (!(relativeToNativeNode instanceof ReadOnlyNode)) {
if (__DEV__) {
console.error(
'Warning: ref.measureLayout must be called with a ref to a native component.',
);
}
return;
}
const toStateNode = getShadowNode(this);
const fromStateNode = getShadowNode(relativeToNativeNode);
if (toStateNode != null && fromStateNode != null) {
nullthrows(getFabricUIManager()).measureLayout(
toStateNode,
fromStateNode,
onFail != null ? onFail : noop,
onSuccess != null ? onSuccess : noop,
);
}
}
setNativeProps(nativeProps: {...}): void {
if (__DEV__) {
warnForStyleProps(nativeProps, this._viewConfig.validAttributes);
}
const updatePayload = createAttributePayload(
nativeProps,
this._viewConfig.validAttributes,
);
const node = getShadowNode(this);
if (node != null && updatePayload != null) {
nullthrows(getFabricUIManager()).setNativeProps(node, updatePayload);
}
}
}

View File

@@ -0,0 +1,72 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
// flowlint unsafe-getters-setters:off
import type ReadOnlyElement from './ReadOnlyElement';
import {getFabricUIManager} from '../../../../../Libraries/ReactNative/FabricUIManager';
import ReadOnlyNode, {getShadowNode} from './ReadOnlyNode';
import {getElementSibling} from './utilities/Traversal';
import nullthrows from 'nullthrows';
export default class ReadOnlyCharacterData extends ReadOnlyNode {
get nextElementSibling(): ReadOnlyElement | null {
return getElementSibling(this, 'next');
}
get previousElementSibling(): ReadOnlyElement | null {
return getElementSibling(this, 'previous');
}
get data(): string {
const shadowNode = getShadowNode(this);
if (shadowNode != null) {
return nullthrows(getFabricUIManager()).getTextContent(shadowNode);
}
return '';
}
get length(): number {
return this.data.length;
}
/**
* @override
*/
get textContent(): string | null {
return this.data;
}
/**
* @override
*/
get nodeValue(): string {
return this.data;
}
substringData(offset: number, count: number): string {
const data = this.data;
if (offset < 0) {
throw new TypeError(
`Failed to execute 'substringData' on 'CharacterData': The offset ${offset} is negative.`,
);
}
if (offset > data.length) {
throw new TypeError(
`Failed to execute 'substringData' on 'CharacterData': The offset ${offset} is greater than the node's length (${data.length}).`,
);
}
let adjustedCount = count < 0 || count > data.length ? data.length : count;
return data.slice(offset, offset + adjustedCount);
}
}

View File

@@ -0,0 +1,277 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
// flowlint unsafe-getters-setters:off
import type HTMLCollection from '../oldstylecollections/HTMLCollection';
import {getFabricUIManager} from '../../../../../Libraries/ReactNative/FabricUIManager';
import DOMRect from '../geometry/DOMRect';
import {createHTMLCollection} from '../oldstylecollections/HTMLCollection';
import ReadOnlyNode, {
getChildNodes,
getInstanceHandle,
getShadowNode,
} from './ReadOnlyNode';
import {getElementSibling} from './utilities/Traversal';
import nullthrows from 'nullthrows';
export default class ReadOnlyElement extends ReadOnlyNode {
get childElementCount(): number {
return getChildElements(this).length;
}
get children(): HTMLCollection<ReadOnlyElement> {
return createHTMLCollection(getChildElements(this));
}
get clientHeight(): number {
const node = getShadowNode(this);
if (node != null) {
const innerSize = nullthrows(getFabricUIManager()).getInnerSize(node);
if (innerSize != null) {
return innerSize[1];
}
}
return 0;
}
get clientLeft(): number {
const node = getShadowNode(this);
if (node != null) {
const borderSize = nullthrows(getFabricUIManager()).getBorderSize(node);
if (borderSize != null) {
return borderSize[3];
}
}
return 0;
}
get clientTop(): number {
const node = getShadowNode(this);
if (node != null) {
const borderSize = nullthrows(getFabricUIManager()).getBorderSize(node);
if (borderSize != null) {
return borderSize[0];
}
}
return 0;
}
get clientWidth(): number {
const node = getShadowNode(this);
if (node != null) {
const innerSize = nullthrows(getFabricUIManager()).getInnerSize(node);
if (innerSize != null) {
return innerSize[0];
}
}
return 0;
}
get firstElementChild(): ReadOnlyElement | null {
const childElements = getChildElements(this);
if (childElements.length === 0) {
return null;
}
return childElements[0];
}
get id(): string {
const instanceHandle = getInstanceHandle(this);
// TODO: migrate off this private React API
// $FlowExpectedError[incompatible-use]
const props = instanceHandle?.stateNode?.canonical?.currentProps;
return props?.id ?? props?.nativeID ?? '';
}
get lastElementChild(): ReadOnlyElement | null {
const childElements = getChildElements(this);
if (childElements.length === 0) {
return null;
}
return childElements[childElements.length - 1];
}
get nextElementSibling(): ReadOnlyElement | null {
return getElementSibling(this, 'next');
}
get nodeName(): string {
return this.tagName;
}
get nodeType(): number {
return ReadOnlyNode.ELEMENT_NODE;
}
get nodeValue(): string | null {
return null;
}
set nodeValue(value: string): void {}
get previousElementSibling(): ReadOnlyElement | null {
return getElementSibling(this, 'previous');
}
get scrollHeight(): number {
const node = getShadowNode(this);
if (node != null) {
const scrollSize = nullthrows(getFabricUIManager()).getScrollSize(node);
if (scrollSize != null) {
return scrollSize[1];
}
}
return 0;
}
get scrollLeft(): number {
const node = getShadowNode(this);
if (node != null) {
const scrollPosition = nullthrows(getFabricUIManager()).getScrollPosition(
node,
);
if (scrollPosition != null) {
return scrollPosition[0];
}
}
return 0;
}
get scrollTop(): number {
const node = getShadowNode(this);
if (node != null) {
const scrollPosition = nullthrows(getFabricUIManager()).getScrollPosition(
node,
);
if (scrollPosition != null) {
return scrollPosition[1];
}
}
return 0;
}
get scrollWidth(): number {
const node = getShadowNode(this);
if (node != null) {
const scrollSize = nullthrows(getFabricUIManager()).getScrollSize(node);
if (scrollSize != null) {
return scrollSize[0];
}
}
return 0;
}
get tagName(): string {
const node = getShadowNode(this);
if (node != null) {
return nullthrows(getFabricUIManager()).getTagName(node);
}
return '';
}
get textContent(): string | null {
const shadowNode = getShadowNode(this);
if (shadowNode != null) {
return nullthrows(getFabricUIManager()).getTextContent(shadowNode);
}
return '';
}
getBoundingClientRect(): DOMRect {
return getBoundingClientRect(this, {includeTransform: true});
}
/**
* Pointer Capture APIs
*/
hasPointerCapture(pointerId: number): boolean {
const node = getShadowNode(this);
if (node != null) {
return nullthrows(getFabricUIManager()).hasPointerCapture(
node,
pointerId,
);
}
return false;
}
setPointerCapture(pointerId: number): void {
const node = getShadowNode(this);
if (node != null) {
nullthrows(getFabricUIManager()).setPointerCapture(node, pointerId);
}
}
releasePointerCapture(pointerId: number): void {
const node = getShadowNode(this);
if (node != null) {
nullthrows(getFabricUIManager()).releasePointerCapture(node, pointerId);
}
}
}
function getChildElements(node: ReadOnlyNode): $ReadOnlyArray<ReadOnlyElement> {
// $FlowIssue[incompatible-call]
return getChildNodes(node).filter(
childNode => childNode instanceof ReadOnlyElement,
);
}
/**
* The public API for `getBoundingClientRect` always includes transform,
* so we use this internal version to get the data without transform to
* implement methods like `offsetWidth` and `offsetHeight`.
*/
export function getBoundingClientRect(
node: ReadOnlyElement,
{includeTransform}: {includeTransform: boolean},
): DOMRect {
const shadowNode = getShadowNode(node);
if (shadowNode != null) {
const rect = nullthrows(getFabricUIManager()).getBoundingClientRect(
shadowNode,
includeTransform,
);
if (rect) {
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
}
}
// Empty rect if any of the above failed
return new DOMRect(0, 0, 0, 0);
}

View File

@@ -0,0 +1,365 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
// flowlint unsafe-getters-setters:off
import type {
InternalInstanceHandle,
Node as ShadowNode,
} from '../../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type NodeList from '../oldstylecollections/NodeList';
import type ReadOnlyElement from './ReadOnlyElement';
import {getFabricUIManager} from '../../../../../Libraries/ReactNative/FabricUIManager';
import {createNodeList} from '../oldstylecollections/NodeList';
import nullthrows from 'nullthrows';
// We initialize this lazily to avoid a require cycle
// (`ReadOnlyElement` also depends on `ReadOnlyNode`).
let ReadOnlyElementClass: Class<ReadOnlyElement>;
export default class ReadOnlyNode {
constructor(internalInstanceHandle: InternalInstanceHandle) {
setInstanceHandle(this, internalInstanceHandle);
}
get childNodes(): NodeList<ReadOnlyNode> {
const childNodes = getChildNodes(this);
return createNodeList(childNodes);
}
get firstChild(): ReadOnlyNode | null {
const childNodes = getChildNodes(this);
if (childNodes.length === 0) {
return null;
}
return childNodes[0];
}
get isConnected(): boolean {
const shadowNode = getShadowNode(this);
if (shadowNode == null) {
return false;
}
return nullthrows(getFabricUIManager()).isConnected(shadowNode);
}
get lastChild(): ReadOnlyNode | null {
const childNodes = getChildNodes(this);
if (childNodes.length === 0) {
return null;
}
return childNodes[childNodes.length - 1];
}
get nextSibling(): ReadOnlyNode | null {
const [siblings, position] = getNodeSiblingsAndPosition(this);
if (position === siblings.length - 1) {
// this node is the last child of its parent, so there is no next sibling.
return null;
}
return siblings[position + 1];
}
/**
* @abstract
*/
get nodeName(): string {
throw new TypeError(
'`nodeName` is abstract and must be implemented in a subclass of `ReadOnlyNode`',
);
}
/**
* @abstract
*/
get nodeType(): number {
throw new TypeError(
'`nodeType` is abstract and must be implemented in a subclass of `ReadOnlyNode`',
);
}
/**
* @abstract
*/
get nodeValue(): string | null {
throw new TypeError(
'`nodeValue` is abstract and must be implemented in a subclass of `ReadOnlyNode`',
);
}
get parentElement(): ReadOnlyElement | null {
const parentNode = this.parentNode;
if (ReadOnlyElementClass == null) {
// We initialize this lazily to avoid a require cycle.
ReadOnlyElementClass = require('./ReadOnlyElement').default;
}
if (parentNode instanceof ReadOnlyElementClass) {
return parentNode;
}
return null;
}
get parentNode(): ReadOnlyNode | null {
const shadowNode = getShadowNode(this);
if (shadowNode == null) {
return null;
}
const parentInstanceHandle = nullthrows(getFabricUIManager()).getParentNode(
shadowNode,
);
if (parentInstanceHandle == null) {
return null;
}
return (
getPublicInstanceFromInternalInstanceHandle(parentInstanceHandle) ?? null
);
}
get previousSibling(): ReadOnlyNode | null {
const [siblings, position] = getNodeSiblingsAndPosition(this);
if (position === 0) {
// this node is the first child of its parent, so there is no previous sibling.
return null;
}
return siblings[position - 1];
}
/**
* @abstract
*/
get textContent(): string | null {
throw new TypeError(
'`textContent` is abstract and must be implemented in a subclass of `ReadOnlyNode`',
);
}
compareDocumentPosition(otherNode: ReadOnlyNode): number {
// Quick check to avoid having to call into Fabric if the nodes are the same.
if (otherNode === this) {
return 0;
}
const shadowNode = getShadowNode(this);
const otherShadowNode = getShadowNode(otherNode);
if (shadowNode == null || otherShadowNode == null) {
return ReadOnlyNode.DOCUMENT_POSITION_DISCONNECTED;
}
return nullthrows(getFabricUIManager()).compareDocumentPosition(
shadowNode,
otherShadowNode,
);
}
contains(otherNode: ReadOnlyNode): boolean {
if (otherNode === this) {
return true;
}
const position = this.compareDocumentPosition(otherNode);
// eslint-disable-next-line no-bitwise
return (position & ReadOnlyNode.DOCUMENT_POSITION_CONTAINED_BY) !== 0;
}
getRootNode(): ReadOnlyNode {
// eslint-disable-next-line consistent-this
let lastKnownParent: ReadOnlyNode = this;
let nextPossibleParent: ?ReadOnlyNode = this.parentNode;
while (nextPossibleParent != null) {
lastKnownParent = nextPossibleParent;
nextPossibleParent = nextPossibleParent.parentNode;
}
return lastKnownParent;
}
hasChildNodes(): boolean {
return getChildNodes(this).length > 0;
}
/*
* Node types, as returned by the `nodeType` property.
*/
/**
* Type of Element, HTMLElement and ReactNativeElement instances.
*/
static ELEMENT_NODE: number = 1;
/**
* Currently Unused in React Native.
*/
static ATTRIBUTE_NODE: number = 2;
/**
* Text nodes.
*/
static TEXT_NODE: number = 3;
/**
* @deprecated Unused in React Native.
*/
static CDATA_SECTION_NODE: number = 4;
/**
* @deprecated
*/
static ENTITY_REFERENCE_NODE: number = 5;
/**
* @deprecated
*/
static ENTITY_NODE: number = 6;
/**
* @deprecated Unused in React Native.
*/
static PROCESSING_INSTRUCTION_NODE: number = 7;
/**
* @deprecated Unused in React Native.
*/
static COMMENT_NODE: number = 8;
/**
* @deprecated Unused in React Native.
*/
static DOCUMENT_NODE: number = 9;
/**
* @deprecated Unused in React Native.
*/
static DOCUMENT_TYPE_NODE: number = 10;
/**
* @deprecated Unused in React Native.
*/
static DOCUMENT_FRAGMENT_NODE: number = 11;
/**
* @deprecated
*/
static NOTATION_NODE: number = 12;
/*
* Document position flags. Used to check the return value of
* `compareDocumentPosition()`.
*/
/**
* Both nodes are in different documents.
*/
static DOCUMENT_POSITION_DISCONNECTED: number = 1;
/**
* `otherNode` precedes the node in either a pre-order depth-first traversal of a tree containing both
* (e.g., as an ancestor or previous sibling or a descendant of a previous sibling or previous sibling of an ancestor)
* or (if they are disconnected) in an arbitrary but consistent ordering.
*/
static DOCUMENT_POSITION_PRECEDING: number = 2;
/**
* `otherNode` follows the node in either a pre-order depth-first traversal of a tree containing both
* (e.g., as a descendant or following sibling or a descendant of a following sibling or following sibling of an ancestor)
* or (if they are disconnected) in an arbitrary but consistent ordering.
*/
static DOCUMENT_POSITION_FOLLOWING: number = 4;
/**
* `otherNode` is an ancestor of the node.
*/
static DOCUMENT_POSITION_CONTAINS: number = 8;
/**
* `otherNode` is a descendant of the node.
*/
static DOCUMENT_POSITION_CONTAINED_BY: number = 16;
/**
* @deprecated Unused in React Native.
*/
static DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: number = 32;
}
const INSTANCE_HANDLE_KEY = Symbol('internalInstanceHandle');
export function getInstanceHandle(node: ReadOnlyNode): InternalInstanceHandle {
// $FlowExpectedError[prop-missing]
return node[INSTANCE_HANDLE_KEY];
}
function setInstanceHandle(
node: ReadOnlyNode,
instanceHandle: InternalInstanceHandle,
): void {
// $FlowExpectedError[prop-missing]
node[INSTANCE_HANDLE_KEY] = instanceHandle;
}
export function getShadowNode(node: ReadOnlyNode): ?ShadowNode {
// Lazy import Fabric here to avoid DOM Node APIs classes from having side-effects.
// With a static import we can't use these classes for Paper-only variants.
const ReactFabric = require('../../../../../Libraries/Renderer/shims/ReactFabric');
return ReactFabric.getNodeFromInternalInstanceHandle(getInstanceHandle(node));
}
export function getChildNodes(
node: ReadOnlyNode,
): $ReadOnlyArray<ReadOnlyNode> {
const shadowNode = getShadowNode(node);
if (shadowNode == null) {
return [];
}
const childNodeInstanceHandles = nullthrows(
getFabricUIManager(),
).getChildNodes(shadowNode);
return childNodeInstanceHandles
.map(instanceHandle =>
getPublicInstanceFromInternalInstanceHandle(instanceHandle),
)
.filter(Boolean);
}
function getNodeSiblingsAndPosition(
node: ReadOnlyNode,
): [$ReadOnlyArray<ReadOnlyNode>, number] {
const parent = node.parentNode;
if (parent == null) {
// This node is the root or it's disconnected.
return [[node], 0];
}
const siblings = getChildNodes(parent);
const position = siblings.indexOf(node);
if (position === -1) {
throw new TypeError("Missing node in parent's child node list");
}
return [siblings, position];
}
export function getPublicInstanceFromInternalInstanceHandle(
instanceHandle: InternalInstanceHandle,
): ?ReadOnlyNode {
// Lazy import Fabric here to avoid DOM Node APIs classes from having side-effects.
// With a static import we can't use these classes for Paper-only variants.
const ReactFabric = require('../../../../../Libraries/Renderer/shims/ReactFabric');
const mixedPublicInstance =
ReactFabric.getPublicInstanceFromInternalInstanceHandle(instanceHandle);
// $FlowExpectedError[incompatible-return] React defines public instances as "mixed" because it can't access the definition from React Native.
return mixedPublicInstance;
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
// flowlint unsafe-getters-setters:off
import ReadOnlyCharacterData from './ReadOnlyCharacterData';
import ReadOnlyNode from './ReadOnlyNode';
export default class ReadOnlyText extends ReadOnlyCharacterData {
/**
* @override
*/
get nodeName(): string {
return '#text';
}
/**
* @override
*/
get nodeType(): number {
return ReadOnlyNode.TEXT_NODE;
}
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict-local
*/
import type ReadOnlyElement from '../ReadOnlyElement';
import type ReadOnlyNode from '../ReadOnlyNode';
import {getChildNodes} from '../ReadOnlyNode';
// We initialize this lazily to avoid a require cycle
// (`ReadOnlyElement` also depends on `Traversal`).
let ReadOnlyElementClass: Class<ReadOnlyElement>;
export function getElementSibling(
node: ReadOnlyNode,
direction: 'next' | 'previous',
): ReadOnlyElement | null {
const parent = node.parentNode;
if (parent == null) {
// This node is the root or it's disconnected.
return null;
}
const childNodes = getChildNodes(parent);
const startPosition = childNodes.indexOf(node);
if (startPosition === -1) {
return null;
}
const increment = direction === 'next' ? 1 : -1;
let position = startPosition + increment;
if (ReadOnlyElementClass == null) {
// We initialize this lazily to avoid a require cycle.
ReadOnlyElementClass = require('../ReadOnlyElement').default;
}
while (
childNodes[position] != null &&
!(childNodes[position] instanceof ReadOnlyElementClass)
) {
position = position + increment;
}
return childNodes[position] ?? null;
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
/**
* This definition is different from the current built-in type `$ArrayLike`
* provided by Flow, in that this is an interface and that one is an object.
*
* The difference is important because, when using objects, Flow thinks
* a `length` property would be copied over when using the spread operator,
* which is incorrect.
*/
export interface ArrayLike<T> extends Iterable<T> {
// This property should've been read-only as well, but Flow doesn't handle
// read-only indexers correctly (thinks reads are writes and fails).
[indexer: number]: T;
+length: number;
}
export function* createValueIterator<T>(arrayLike: ArrayLike<T>): Iterator<T> {
for (let i = 0; i < arrayLike.length; i++) {
yield arrayLike[i];
}
}
export function* createKeyIterator<T>(
arrayLike: ArrayLike<T>,
): Iterator<number> {
for (let i = 0; i < arrayLike.length; i++) {
yield i;
}
}
export function* createEntriesIterator<T>(
arrayLike: ArrayLike<T>,
): Iterator<[number, T]> {
for (let i = 0; i < arrayLike.length; i++) {
yield [i, arrayLike[i]];
}
}

View File

@@ -0,0 +1,76 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
// flowlint unsafe-getters-setters:off
import type DOMRectReadOnly from '../geometry/DOMRectReadOnly';
import type {ArrayLike} from './ArrayLikeUtils';
import {createValueIterator} from './ArrayLikeUtils';
// IMPORTANT: The Flow type definition for this module is defined in `DOMRectList.js.flow`
// because Flow only supports indexers in classes in declaration files.
// $FlowIssue[prop-missing] Flow doesn't understand [Symbol.iterator]() {} and thinks this class doesn't implement the Iterable interface.
export default class DOMRectList implements Iterable<DOMRectReadOnly> {
_length: number;
/**
* Use `createDOMRectList` to create instances of this class.
*
* @private This is not defined in the declaration file, so users will not see
* the signature of the constructor.
*/
constructor(elements: $ReadOnlyArray<DOMRectReadOnly>) {
for (let i = 0; i < elements.length; i++) {
Object.defineProperty(this, i, {
value: elements[i],
enumerable: true,
configurable: false,
writable: false,
});
}
this._length = elements.length;
}
get length(): number {
return this._length;
}
item(index: number): DOMRectReadOnly | null {
if (index < 0 || index >= this._length) {
return null;
}
// assigning to the interface allows us to access the indexer property in a
// type-safe way.
// eslint-disable-next-line consistent-this
const arrayLike: ArrayLike<DOMRectReadOnly> = this;
return arrayLike[index];
}
// $FlowIssue[unsupported-syntax] Flow does not support computed properties in classes.
[Symbol.iterator](): Iterator<DOMRectReadOnly> {
return createValueIterator(this);
}
}
/**
* This is an internal method to create instances of `DOMRectList`,
* which avoids leaking its constructor to end users.
* We can do that because the external definition of `DOMRectList` lives in
* `DOMRectList.js.flow`, not here.
*/
export function createDOMRectList(
elements: $ReadOnlyArray<DOMRectReadOnly>,
): DOMRectList {
return new DOMRectList(elements);
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
import type DOMRectReadOnly from '../geometry/DOMRectReadOnly';
import type {ArrayLike} from './ArrayLikeUtils';
declare export default class DOMRectList
implements Iterable<DOMRectReadOnly>, ArrayLike<DOMRectReadOnly>
{
// This property should've been read-only as well, but Flow doesn't handle
// read-only indexers correctly (thinks reads are writes and fails).
[index: number]: DOMRectReadOnly;
+length: number;
item(index: number): DOMRectReadOnly | null;
@@iterator(): Iterator<DOMRectReadOnly>;
}
declare export function createDOMRectList(
domRects: $ReadOnlyArray<DOMRectReadOnly>,
): DOMRectList;

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
// flowlint unsafe-getters-setters:off
import type {ArrayLike} from './ArrayLikeUtils';
import {createValueIterator} from './ArrayLikeUtils';
// IMPORTANT: The type definition for this module is defined in `HTMLCollection.js.flow`
// because Flow only supports indexers in classes in declaration files.
// $FlowIssue[prop-missing] Flow doesn't understand [Symbol.iterator]() {} and thinks this class doesn't implement the Iterable<T> interface.
export default class HTMLCollection<T> implements Iterable<T>, ArrayLike<T> {
_length: number;
/**
* Use `createHTMLCollection` to create instances of this class.
*
* @private This is not defined in the declaration file, so users will not see
* the signature of the constructor.
*/
constructor(elements: $ReadOnlyArray<T>) {
for (let i = 0; i < elements.length; i++) {
Object.defineProperty(this, i, {
value: elements[i],
enumerable: true,
configurable: false,
writable: false,
});
}
this._length = elements.length;
}
get length(): number {
return this._length;
}
item(index: number): T | null {
if (index < 0 || index >= this._length) {
return null;
}
// assigning to the interface allows us to access the indexer property in a
// type-safe way.
// eslint-disable-next-line consistent-this
const arrayLike: ArrayLike<T> = this;
return arrayLike[index];
}
/**
* @deprecated Unused in React Native.
*/
namedItem(name: string): T | null {
return null;
}
// $FlowIssue[unsupported-syntax] Flow does not support computed properties in classes.
[Symbol.iterator](): Iterator<T> {
return createValueIterator(this);
}
}
/**
* This is an internal method to create instances of `HTMLCollection`,
* which avoids leaking its constructor to end users.
* We can do that because the external definition of `HTMLCollection` lives in
* `HTMLCollection.js.flow`, not here.
*/
export function createHTMLCollection<T>(
elements: $ReadOnlyArray<T>,
): HTMLCollection<T> {
return new HTMLCollection(elements);
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
import type {ArrayLike} from './ArrayLikeUtils';
declare export default class HTMLCollection<+T>
implements Iterable<T>, ArrayLike<T>
{
// This property should've been read-only as well, but Flow doesn't handle
// read-only indexers correctly (thinks reads are writes and fails).
[index: number]: T;
+length: number;
item(index: number): T | null;
namedItem(name: string): T | null;
@@iterator(): Iterator<T>;
}
declare export function createHTMLCollection<T>(
elements: $ReadOnlyArray<T>,
): HTMLCollection<T>;

View File

@@ -0,0 +1,104 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
// flowlint unsafe-getters-setters:off
import type {ArrayLike} from './ArrayLikeUtils';
import {
createEntriesIterator,
createKeyIterator,
createValueIterator,
} from './ArrayLikeUtils';
// IMPORTANT: The Flow type definition for this module is defined in `NodeList.js.flow`
// because Flow only supports indexers in classes in declaration files.
// $FlowIssue[prop-missing] Flow doesn't understand [Symbol.iterator]() {} and thinks this class doesn't implement the Iterable<T> interface.
export default class NodeList<T> implements Iterable<T>, ArrayLike<T> {
_length: number;
/**
* Use `createNodeList` to create instances of this class.
*
* @private This is not defined in the declaration file, so users will not see
* the signature of the constructor.
*/
constructor(elements: $ReadOnlyArray<T>) {
for (let i = 0; i < elements.length; i++) {
Object.defineProperty(this, i, {
value: elements[i],
writable: false,
});
}
this._length = elements.length;
}
get length(): number {
return this._length;
}
item(index: number): T | null {
if (index < 0 || index >= this._length) {
return null;
}
// assigning to the interface allows us to access the indexer property in a
// type-safe way.
// eslint-disable-next-line consistent-this
const arrayLike: ArrayLike<T> = this;
return arrayLike[index];
}
entries(): Iterator<[number, T]> {
return createEntriesIterator(this);
}
forEach<ThisType>(
callbackFn: (value: T, index: number, array: NodeList<T>) => mixed,
thisArg?: ThisType,
): void {
// assigning to the interface allows us to access the indexer property in a
// type-safe way.
// eslint-disable-next-line consistent-this
const arrayLike: ArrayLike<T> = this;
for (let index = 0; index < this._length; index++) {
if (thisArg == null) {
callbackFn(arrayLike[index], index, this);
} else {
callbackFn.call(thisArg, arrayLike[index], index, this);
}
}
}
keys(): Iterator<number> {
return createKeyIterator(this);
}
values(): Iterator<T> {
return createValueIterator(this);
}
// $FlowIssue[unsupported-syntax] Flow does not support computed properties in classes.
[Symbol.iterator](): Iterator<T> {
return createValueIterator(this);
}
}
/**
* This is an internal method to create instances of `NodeList`,
* which avoids leaking its constructor to end users.
* We can do that because the external definition of `NodeList` lives in
* `NodeList.js.flow`, not here.
*/
export function createNodeList<T>(elements: $ReadOnlyArray<T>): NodeList<T> {
return new NodeList(elements);
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow strict
*/
import type {ArrayLike} from './ArrayLikeUtils';
declare export default class NodeList<+T> implements Iterable<T>, ArrayLike<T> {
// This property should've been read-only as well, but Flow doesn't handle
// read-only indexers correctly (thinks reads are writes and fails).
[index: number]: T;
+length: number;
item(index: number): T | null;
entries(): Iterator<[number, T]>;
forEach<ThisType>(
callbackFn: (value: T, index: number, array: NodeList<T>) => mixed,
thisArg?: ThisType,
): void;
keys(): Iterator<number>;
values(): Iterator<T>;
@@iterator(): Iterator<T>;
}
declare export function createNodeList<T>(
elements: $ReadOnlyArray<T>,
): NodeList<T>;

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
* @oncall react_native
*/
import DOMRectReadOnly from '../../geometry/DOMRectReadOnly';
import {createDOMRectList} from '../DOMRectList';
const domRectA = new DOMRectReadOnly();
const domRectB = new DOMRectReadOnly();
const domRectC = new DOMRectReadOnly();
describe('DOMRectList', () => {
it('provides an array-like interface', () => {
const collection = createDOMRectList([domRectA, domRectB, domRectC]);
expect(collection[0]).toBe(domRectA);
expect(collection[1]).toBe(domRectB);
expect(collection[2]).toBe(domRectC);
expect(collection[3]).toBe(undefined);
expect(collection.length).toBe(3);
});
it('is immutable (loose mode)', () => {
const collection = createDOMRectList([domRectA, domRectB, domRectC]);
collection[0] = new DOMRectReadOnly();
expect(collection[0]).toBe(domRectA);
// $FlowExpectedError[cannot-write]
collection.length = 100;
expect(collection.length).toBe(3);
});
it('is immutable (strict mode)', () => {
'use strict';
const collection = createDOMRectList([domRectA, domRectB, domRectC]);
expect(() => {
collection[0] = new DOMRectReadOnly();
}).toThrow(TypeError);
expect(collection[0]).toBe(domRectA);
expect(() => {
// $FlowExpectedError[cannot-write]
collection.length = 100;
}).toThrow(TypeError);
expect(collection.length).toBe(3);
});
it('can be converted to an array through common methods', () => {
const collection = createDOMRectList([domRectA, domRectB, domRectC]);
expect(Array.from(collection)).toEqual([domRectA, domRectB, domRectC]);
expect([...collection]).toEqual([domRectA, domRectB, domRectC]);
});
it('can be traversed with for-of', () => {
const collection = createDOMRectList([domRectA, domRectB, domRectC]);
let i = 0;
for (const value of collection) {
expect(value).toBe(collection[i]);
i++;
}
});
describe('item()', () => {
it('returns elements at the specified position, or null', () => {
const collection = createDOMRectList([domRectA, domRectB, domRectC]);
expect(collection.item(0)).toBe(domRectA);
expect(collection.item(1)).toBe(domRectB);
expect(collection.item(2)).toBe(domRectC);
expect(collection.item(3)).toBe(null);
});
});
});

View File

@@ -0,0 +1,80 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
* @oncall react_native
*/
import {createHTMLCollection} from '../HTMLCollection';
describe('HTMLCollection', () => {
it('provides an array-like interface', () => {
const collection = createHTMLCollection(['a', 'b', 'c']);
expect(collection[0]).toBe('a');
expect(collection[1]).toBe('b');
expect(collection[2]).toBe('c');
expect(collection[3]).toBe(undefined);
expect(collection.length).toBe(3);
});
it('is immutable (loose mode)', () => {
const collection = createHTMLCollection(['a', 'b', 'c']);
collection[0] = 'replacement';
expect(collection[0]).toBe('a');
// $FlowExpectedError[cannot-write]
collection.length = 100;
expect(collection.length).toBe(3);
});
it('is immutable (strict mode)', () => {
'use strict';
const collection = createHTMLCollection(['a', 'b', 'c']);
expect(() => {
collection[0] = 'replacement';
}).toThrow(TypeError);
expect(collection[0]).toBe('a');
expect(() => {
// $FlowExpectedError[cannot-write]
collection.length = 100;
}).toThrow(TypeError);
expect(collection.length).toBe(3);
});
it('can be converted to an array through common methods', () => {
const collection = createHTMLCollection(['a', 'b', 'c']);
expect(Array.from(collection)).toEqual(['a', 'b', 'c']);
expect([...collection]).toEqual(['a', 'b', 'c']);
});
it('can be traversed with for-of', () => {
const collection = createHTMLCollection(['a', 'b', 'c']);
let i = 0;
for (const value of collection) {
expect(value).toBe(collection[i]);
i++;
}
});
describe('item()', () => {
it('returns elements at the specified position, or null', () => {
const collection = createHTMLCollection(['a', 'b', 'c']);
expect(collection.item(0)).toBe('a');
expect(collection.item(1)).toBe('b');
expect(collection.item(2)).toBe('c');
expect(collection.item(3)).toBe(null);
});
});
});

View File

@@ -0,0 +1,161 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* 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
* @oncall react_native
*/
import {createNodeList} from '../NodeList';
describe('NodeList', () => {
it('provides an array-like interface', () => {
const collection = createNodeList(['a', 'b', 'c']);
expect(collection[0]).toBe('a');
expect(collection[1]).toBe('b');
expect(collection[2]).toBe('c');
expect(collection[3]).toBe(undefined);
expect(collection.length).toBe(3);
});
it('provides indexed access through the item method', () => {
const collection = createNodeList(['a', 'b', 'c']);
expect(collection.item(0)).toBe('a');
expect(collection.item(1)).toBe('b');
expect(collection.item(2)).toBe('c');
expect(collection.item(3)).toBe(null);
});
it('is immutable (loose mode)', () => {
const collection = createNodeList(['a', 'b', 'c']);
collection[0] = 'replacement';
expect(collection[0]).toBe('a');
// $FlowExpectedError[cannot-write]
collection.length = 100;
expect(collection.length).toBe(3);
});
it('is immutable (strict mode)', () => {
'use strict';
const collection = createNodeList(['a', 'b', 'c']);
expect(() => {
collection[0] = 'replacement';
}).toThrow(TypeError);
expect(collection[0]).toBe('a');
expect(() => {
// $FlowExpectedError[cannot-write]
collection.length = 100;
}).toThrow(TypeError);
expect(collection.length).toBe(3);
});
it('can be converted to an array through common methods', () => {
const collection = createNodeList(['a', 'b', 'c']);
expect(Array.from(collection)).toEqual(['a', 'b', 'c']);
expect([...collection]).toEqual(['a', 'b', 'c']);
});
it('can be traversed with for-of', () => {
const collection = createNodeList(['a', 'b', 'c']);
let i = 0;
for (const value of collection) {
expect(value).toBe(collection[i]);
i++;
}
});
describe('keys()', () => {
it('returns an iterator for keys', () => {
const collection = createNodeList(['a', 'b', 'c']);
const keys = collection.keys();
expect(keys.next()).toEqual({value: 0, done: false});
expect(keys.next()).toEqual({value: 1, done: false});
expect(keys.next()).toEqual({value: 2, done: false});
expect(keys.next()).toEqual({done: true});
let i = 0;
for (const key of collection.keys()) {
expect(key).toBe(i);
i++;
}
});
});
describe('values()', () => {
it('returns an iterator for values', () => {
const collection = createNodeList(['a', 'b', 'c']);
const values = collection.values();
expect(values.next()).toEqual({value: 'a', done: false});
expect(values.next()).toEqual({value: 'b', done: false});
expect(values.next()).toEqual({value: 'c', done: false});
expect(values.next()).toEqual({done: true});
let i = 0;
for (const value of collection.values()) {
expect(value).toBe(collection[i]);
i++;
}
});
});
describe('entries()', () => {
it('returns an iterator for entries', () => {
const collection = createNodeList(['a', 'b', 'c']);
const entries = collection.entries();
expect(entries.next()).toEqual({value: [0, 'a'], done: false});
expect(entries.next()).toEqual({value: [1, 'b'], done: false});
expect(entries.next()).toEqual({value: [2, 'c'], done: false});
expect(entries.next()).toEqual({done: true});
let i = 0;
for (const entry of collection.entries()) {
expect(entry).toEqual([i, collection[i]]);
i++;
}
});
});
describe('forEach()', () => {
it('iterates over the elements like array.forEach (implicit `this`)', () => {
const collection = createNodeList(['a', 'b', 'c']);
let i = 0;
collection.forEach(function (this: mixed, value, index, list) {
expect(value).toBe(collection[i]);
expect(index).toBe(i);
expect(list).toBe(collection);
expect(this).toBe(window);
i++;
});
});
it('iterates over the elements like array.forEach (explicit `this`)', () => {
const collection = createNodeList(['a', 'b', 'c']);
let i = 0;
const explicitThis = {id: 'foo'};
collection.forEach(function (this: mixed, value, index, list) {
expect(value).toBe(collection[i]);
expect(index).toBe(i);
expect(list).toBe(collection);
expect(this).toBe(explicitThis);
i++;
}, explicitThis);
});
});
});

View File

@@ -0,0 +1,244 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <algorithm>
#include <functional>
#include <vector>
namespace facebook::react {
constexpr int DEFAULT_MAX_SIZE = 1024;
/**
* A container for storing entries of type T, with the following properties:
* - It can only grow up to a specified max size
* - It's a circular buffer (the oldest elements are dropped if reached max
* size and adding a new element)
* - The entries can be "consumed" (once), which from the point of view of
* the consumer effectively clears the buffer
* - Even after the entries are consumed, all of the non-overwritten entries
* can still be independently retrieved an arbitrary amount of times
*/
template <class T>
class BoundedConsumableBuffer {
public:
/**
* Status of the add/push operation for the `BoundedConsumableBuffer`
* container
*/
enum class PushStatus {
// There was free space in the buffer, element was successfully pushed:
OK = 0,
// Element was pushed, but had to overwrite some already consumed elements:
OVERWRITE = 1,
// Element wasn't pushed, as buffer size limit has been reached and it's
// not possible to overwrite already consumed elements anymore:
DROP = 2,
};
BoundedConsumableBuffer(int maxSize = DEFAULT_MAX_SIZE) : maxSize_(maxSize) {}
/**
* Adds (pushes) element into the buffer. Returns the result/status of the
* operation, which will depend on whether the buffer reached the max allowed
* size and how many are there unconsumed elements.
*/
PushStatus add(const T&& el) {
if (entries_.size() < maxSize_) {
// Haven't reached max buffer size yet, just add and grow the buffer
entries_.emplace_back(el);
cursorEnd_++;
numToConsume_++;
return PushStatus::OK;
} else if (numToConsume_ == maxSize_) {
// Drop the oldest (yet unconsumed) element in the buffer
entries_[position_] = el;
cursorEnd_ = (cursorEnd_ + 1) % maxSize_;
position_ = (position_ + 1) % maxSize_;
cursorStart_ = position_;
return PushStatus::DROP;
} else {
// Overwrite the oldest (but already consumed) element in the buffer
entries_[position_] = el;
position_ = (position_ + 1) % entries_.size();
cursorEnd_ = position_;
numToConsume_++;
return PushStatus::OVERWRITE;
}
}
/**
* Returns pointer to next entry which would be overwritten or dropped if
* added a new element. Null if no entry will be dropped.
*/
const T* getNextOverwriteCandidate() const {
if (entries_.size() < maxSize_) {
return nullptr;
} else {
return &entries_[position_];
}
}
T& operator[](size_t idx) {
return entries_[(position_ + idx) % entries_.size()];
}
/**
* Returns reference to the last unconsumed element
*/
T& back() {
return entries_[(cursorEnd_ - 1 + entries_.size()) % entries_.size()];
}
size_t size() const {
return entries_.size();
}
size_t getNumToConsume() const {
return numToConsume_;
}
void clear() {
entries_.clear();
position_ = 0;
cursorStart_ = 0;
cursorEnd_ = 0;
numToConsume_ = 0;
}
/**
* Clears buffer entries by predicate
*/
void clear(std::function<bool(const T&)> predicate) {
int pos = cursorStart_;
std::vector<T> entries;
int numToConsume = 0;
int i;
for (i = 0; i < numToConsume_; i++) {
if (!predicate(entries_[pos])) {
entries.push_back(entries_[pos]);
numToConsume++;
}
pos = (pos + 1) % entries_.size();
}
cursorEnd_ = entries.size();
for (; i < entries_.size(); i++) {
if (!predicate(entries_[pos])) {
entries.push_back(entries_[pos]);
}
pos = (pos + 1) % entries_.size();
}
numToConsume_ = numToConsume;
cursorStart_ = 0;
cursorEnd_ = numToConsume_;
position_ = numToConsume_;
entries.swap(entries_);
}
/**
* Retrieves buffer entries, whether consumed or not
*/
std::vector<T> getEntries() const {
std::vector<T> res;
getEntries(res);
return res;
}
/**
* Retrieves buffer entries, whether consumed or not, with predicate
*/
std::vector<T> getEntries(std::function<bool(const T&)> predicate) const {
std::vector<T> res;
getEntries(res, predicate);
return res;
}
void getEntries(std::vector<T>& res) const {
const size_t oldSize = res.size();
res.resize(oldSize + entries_.size());
std::copy(
entries_.begin() + position_, entries_.end(), res.begin() + oldSize);
std::copy(
entries_.begin(),
entries_.begin() + position_,
res.begin() + oldSize + entries_.size() - position_);
}
void getEntries(std::vector<T>& res, std::function<bool(const T&)> predicate)
const {
for (int i = 0; i < entries_.size(); i++) {
const T& el = entries_[(i + position_) % entries_.size()];
if (predicate(el)) {
res.push_back(el);
}
}
}
/**
* "Consumes" all the currently unconsumed entries in the buffer and returns
* these entries. Note that even if the buffer may not have unconsumed
* elements currently, it's still possible to retrieve all buffer elements
* via `getEntries`.
*/
std::vector<T> consume() {
std::vector<T> res;
consume(res);
return res;
}
void consume(std::vector<T>& res) {
if (numToConsume_ == 0) {
return;
}
const size_t resStart = res.size();
res.resize(res.size() + numToConsume_);
if (cursorEnd_ > cursorStart_) {
std::copy(
entries_.begin() + cursorStart_,
entries_.begin() + cursorEnd_,
res.begin() + resStart);
} else {
std::copy(
entries_.begin() + cursorStart_,
entries_.end(),
res.begin() + resStart);
std::copy(
entries_.begin(),
entries_.begin() + cursorEnd_,
res.begin() + resStart + static_cast<int>(entries_.size()) -
cursorStart_);
}
cursorStart_ = cursorEnd_;
numToConsume_ = 0;
}
private:
std::vector<T> entries_;
const int maxSize_;
// Current starting position in the circular buffer:
int position_{0};
// Current "cursor" - positions of the firsst and after last unconsumed
// element, relative to the starting position:
int cursorStart_{0};
int cursorEnd_{0};
// Number of currently unconsumed elements:
int numToConsume_{0};
};
} // namespace facebook::react

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import NativePerformanceObserver from './NativePerformanceObserver';
import {warnNoNativePerformanceObserver} from './PerformanceObserver';
type EventCountsForEachCallbackType =
| (() => void)
| ((value: number) => void)
| ((value: number, key: string) => void)
| ((value: number, key: string, map: Map<string, number>) => void);
let cachedEventCounts: ?Map<string, number>;
function getCachedEventCounts(): Map<string, number> {
if (cachedEventCounts) {
return cachedEventCounts;
}
if (!NativePerformanceObserver) {
warnNoNativePerformanceObserver();
return new Map();
}
cachedEventCounts = new Map<string, number>(
NativePerformanceObserver.getEventCounts(),
);
// $FlowFixMe[incompatible-call]
global.queueMicrotask(() => {
// To be consistent with the calls to the API from the same task,
// but also not to refetch the data from native too often,
// schedule to invalidate the cache later,
// after the current task is guaranteed to have finished.
cachedEventCounts = null;
});
return cachedEventCounts ?? new Map();
}
/**
* Implementation of the EventCounts Web Performance API
* corresponding to the standard in
* https://www.w3.org/TR/event-timing/#eventcounts
*/
export default class EventCounts {
// flowlint unsafe-getters-setters:off
get size(): number {
return getCachedEventCounts().size;
}
entries(): Iterator<[string, number]> {
return getCachedEventCounts().entries();
}
forEach(callback: EventCountsForEachCallbackType): void {
return getCachedEventCounts().forEach(callback);
}
get(key: string): ?number {
return getCachedEventCounts().get(key);
}
has(key: string): boolean {
return getCachedEventCounts().has(key);
}
keys(): Iterator<string> {
return getCachedEventCounts().keys();
}
values(): Iterator<number> {
return getCachedEventCounts().values();
}
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
* @oncall react_native
*/
// flowlint unsafe-getters-setters:off
type MemoryInfoLike = {
jsHeapSizeLimit: ?number,
totalJSHeapSize: ?number,
usedJSHeapSize: ?number,
};
// Read-only object with JS memory information. This is returned by the performance.memory API.
export default class MemoryInfo {
_jsHeapSizeLimit: ?number;
_totalJSHeapSize: ?number;
_usedJSHeapSize: ?number;
constructor(memoryInfo: ?MemoryInfoLike) {
if (memoryInfo != null) {
this._jsHeapSizeLimit = memoryInfo.jsHeapSizeLimit;
this._totalJSHeapSize = memoryInfo.totalJSHeapSize;
this._usedJSHeapSize = memoryInfo.usedJSHeapSize;
}
}
/**
* The maximum size of the heap, in bytes, that is available to the context
*/
get jsHeapSizeLimit(): ?number {
return this._jsHeapSizeLimit;
}
/**
* The total allocated heap size, in bytes
*/
get totalJSHeapSize(): ?number {
return this._totalJSHeapSize;
}
/**
* The currently active segment of JS heap, in bytes.
*/
get usedJSHeapSize(): ?number {
return this._usedJSHeapSize;
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <memory>
#include <cxxreact/ReactMarker.h>
#include <jsi/instrumentation.h>
#include "NativePerformance.h"
#include "PerformanceEntryReporter.h"
#include "Plugins.h"
std::shared_ptr<facebook::react::TurboModule> NativePerformanceModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativePerformance>(
std::move(jsInvoker));
}
namespace facebook::react {
NativePerformance::NativePerformance(std::shared_ptr<CallInvoker> jsInvoker)
: NativePerformanceCxxSpec(std::move(jsInvoker)) {}
void NativePerformance::mark(
jsi::Runtime& rt,
std::string name,
double startTime) {
PerformanceEntryReporter::getInstance().mark(name, startTime);
}
void NativePerformance::measure(
jsi::Runtime& rt,
std::string name,
double startTime,
double endTime,
std::optional<double> duration,
std::optional<std::string> startMark,
std::optional<std::string> endMark) {
PerformanceEntryReporter::getInstance().measure(
name, startTime, endTime, duration, startMark, endMark);
}
std::unordered_map<std::string, double> NativePerformance::getSimpleMemoryInfo(
jsi::Runtime& rt) {
auto heapInfo = rt.instrumentation().getHeapInfo(false);
std::unordered_map<std::string, double> heapInfoToJs;
for (auto& entry : heapInfo) {
heapInfoToJs[entry.first] = static_cast<double>(entry.second);
}
return heapInfoToJs;
}
std::unordered_map<std::string, double>
NativePerformance::getReactNativeStartupTiming(jsi::Runtime& rt) {
std::unordered_map<std::string, double> result;
ReactMarker::StartupLogger& startupLogger =
ReactMarker::StartupLogger::getInstance();
if (!std::isnan(startupLogger.getAppStartupStartTime())) {
result["startTime"] = startupLogger.getAppStartupStartTime();
} else if (!std::isnan(startupLogger.getInitReactRuntimeStartTime())) {
result["startTime"] = startupLogger.getInitReactRuntimeStartTime();
}
if (!std::isnan(startupLogger.getInitReactRuntimeStartTime())) {
result["initializeRuntimeStart"] =
startupLogger.getInitReactRuntimeStartTime();
}
if (!std::isnan(startupLogger.getRunJSBundleStartTime())) {
result["executeJavaScriptBundleEntryPointStart"] =
startupLogger.getRunJSBundleStartTime();
}
if (!std::isnan(startupLogger.getRunJSBundleEndTime())) {
result["executeJavaScriptBundleEntryPointEnd"] =
startupLogger.getRunJSBundleEndTime();
}
if (!std::isnan(startupLogger.getInitReactRuntimeEndTime())) {
result["initializeRuntimeEnd"] = startupLogger.getInitReactRuntimeEndTime();
}
if (!std::isnan(startupLogger.getAppStartupEndTime())) {
result["endTime"] = startupLogger.getAppStartupEndTime();
}
return result;
}
} // namespace facebook::react

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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 <FBReactNativeSpec/FBReactNativeSpecJSI.h>
#include <memory>
#include <string>
#include "NativePerformanceObserver.h"
namespace facebook::react {
class PerformanceEntryReporter;
#pragma mark - Structs
#pragma mark - implementation
class NativePerformance : public NativePerformanceCxxSpec<NativePerformance>,
std::enable_shared_from_this<NativePerformance> {
public:
NativePerformance(std::shared_ptr<CallInvoker> jsInvoker);
void mark(jsi::Runtime& rt, std::string name, double startTime);
void measure(
jsi::Runtime& rt,
std::string name,
double startTime,
double endTime,
std::optional<double> duration,
std::optional<std::string> startMark,
std::optional<std::string> endMark);
// To align with web API, we will make sure to return three properties
// (jsHeapSizeLimit, totalJSHeapSize, usedJSHeapSize) + anything needed from
// the VM side.
// `jsHeapSizeLimit`: The maximum size of the heap, in bytes, that
// is available to the context.
// `totalJSHeapSize`: The total allocated heap size, in bytes.
// `usedJSHeapSize`: The currently active segment of JS heap, in
// bytes.
//
// Note that we use int64_t here and it's ok to lose precision in JS doubles
// for heap size information, as double's 2^53 sig bytes is large enough.
std::unordered_map<std::string, double> getSimpleMemoryInfo(jsi::Runtime& rt);
// Collect and return the RN app startup timing information for performance
// tracking.
std::unordered_map<std::string, double> getReactNativeStartupTiming(
jsi::Runtime& rt);
private:
};
} // namespace facebook::react

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
import type {TurboModule} from '../../../../Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from '../../../../Libraries/TurboModule/TurboModuleRegistry';
export type NativeMemoryInfo = {[key: string]: ?number};
export type ReactNativeStartupTiming = {[key: string]: ?number};
export interface Spec extends TurboModule {
+mark: (name: string, startTime: number) => void;
+measure: (
name: string,
startTime: number,
endTime: number,
duration?: number,
startMark?: string,
endMark?: string,
) => void;
+getSimpleMemoryInfo: () => NativeMemoryInfo;
+getReactNativeStartupTiming: () => ReactNativeStartupTiming;
}
export default (TurboModuleRegistry.get<Spec>('NativePerformanceCxx'): ?Spec);

Some files were not shown because too many files have changed in this diff Show More