diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer.d.ts b/Libraries/Renderer/implementations/ReactNativeRenderer.d.ts new file mode 100644 index 00000000000..2624d4a78ce --- /dev/null +++ b/Libraries/Renderer/implementations/ReactNativeRenderer.d.ts @@ -0,0 +1,149 @@ +/** + * 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 + */ + +import {GestureResponderEvent} from '../../Types/CoreEventTypes'; + +/** + * Gesture recognition on mobile devices is much more complicated than web. + * A touch can go through several phases as the app determines what the user's intention is. + * For example, the app needs to determine if the touch is scrolling, sliding on a widget, or tapping. + * This can even change during the duration of a touch. There can also be multiple simultaneous touches. + * + * The touch responder system is needed to allow components to negotiate these touch interactions + * without any additional knowledge about their parent or child components. + * This system is implemented in ResponderEventPlugin.js, which contains further details and documentation. + * + * Best Practices + * Users can feel huge differences in the usability of web apps vs. native, and this is one of the big causes. + * Every action should have the following attributes: + * Feedback/highlighting- show the user what is handling their touch, and what will happen when they release the gesture + * Cancel-ability- when making an action, the user should be able to abort it mid-touch by dragging their finger away + * + * These features make users more comfortable while using an app, + * because it allows people to experiment and interact without fear of making mistakes. + * + * TouchableHighlight and Touchable* + * The responder system can be complicated to use. + * So we have provided an abstract Touchable implementation for things that should be "tappable". + * This uses the responder system and allows you to easily configure tap interactions declaratively. + * Use TouchableHighlight anywhere where you would use a button or link on web. + */ +export interface GestureResponderHandlers { + /** + * A view can become the touch responder by implementing the correct negotiation methods. + * There are two methods to ask the view if it wants to become responder: + */ + + /** + * Does this view want to become responder on the start of a touch? + */ + onStartShouldSetResponder?: + | ((event: GestureResponderEvent) => boolean) + | undefined; + + /** + * Called for every touch move on the View when it is not the responder: does this view want to "claim" touch responsiveness? + */ + onMoveShouldSetResponder?: + | ((event: GestureResponderEvent) => boolean) + | undefined; + + /** + * If the View returns true and attempts to become the responder, one of the following will happen: + */ + + onResponderEnd?: ((event: GestureResponderEvent) => void) | undefined; + + /** + * The View is now responding for touch events. + * This is the time to highlight and show the user what is happening + */ + onResponderGrant?: ((event: GestureResponderEvent) => void) | undefined; + + /** + * Something else is the responder right now and will not release it + */ + onResponderReject?: ((event: GestureResponderEvent) => void) | undefined; + + /** + * If the view is responding, the following handlers can be called: + */ + + /** + * The user is moving their finger + */ + onResponderMove?: ((event: GestureResponderEvent) => void) | undefined; + + /** + * Fired at the end of the touch, ie "touchUp" + */ + onResponderRelease?: ((event: GestureResponderEvent) => void) | undefined; + + onResponderStart?: ((event: GestureResponderEvent) => void) | undefined; + + /** + * Something else wants to become responder. + * Should this view release the responder? Returning true allows release + */ + onResponderTerminationRequest?: + | ((event: GestureResponderEvent) => boolean) + | undefined; + + /** + * The responder has been taken from the View. + * Might be taken by other views after a call to onResponderTerminationRequest, + * or might be taken by the OS without asking (happens with control center/ notification center on iOS) + */ + onResponderTerminate?: ((event: GestureResponderEvent) => void) | undefined; + + /** + * onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, + * where the deepest node is called first. + * That means that the deepest component will become responder when multiple Views return true for *ShouldSetResponder handlers. + * This is desirable in most cases, because it makes sure all controls and buttons are usable. + * + * However, sometimes a parent will want to make sure that it becomes responder. + * This can be handled by using the capture phase. + * Before the responder system bubbles up from the deepest component, + * it will do a capture phase, firing on*ShouldSetResponderCapture. + * So if a parent View wants to prevent the child from becoming responder on a touch start, + * it should have a onStartShouldSetResponderCapture handler which returns true. + */ + onStartShouldSetResponderCapture?: + | ((event: GestureResponderEvent) => boolean) + | undefined; + + /** + * onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, + * where the deepest node is called first. + * That means that the deepest component will become responder when multiple Views return true for *ShouldSetResponder handlers. + * This is desirable in most cases, because it makes sure all controls and buttons are usable. + * + * However, sometimes a parent will want to make sure that it becomes responder. + * This can be handled by using the capture phase. + * Before the responder system bubbles up from the deepest component, + * it will do a capture phase, firing on*ShouldSetResponderCapture. + * So if a parent View wants to prevent the child from becoming responder on a touch start, + * it should have a onStartShouldSetResponderCapture handler which returns true. + */ + onMoveShouldSetResponderCapture?: + | ((event: GestureResponderEvent) => boolean) + | undefined; +} + +/** + * React Native also implements unstable_batchedUpdates + */ +export function unstable_batchedUpdates( + callback: (a: A, b: B) => any, + a: A, + b: B, +): void; +export function unstable_batchedUpdates(callback: (a: A) => any, a: A): void; +export function unstable_batchedUpdates(callback: () => any): void; diff --git a/Libraries/Renderer/shims/ReactNativeTypes.d.ts b/Libraries/Renderer/shims/ReactNativeTypes.d.ts new file mode 100644 index 00000000000..38e00e1cc93 --- /dev/null +++ b/Libraries/Renderer/shims/ReactNativeTypes.d.ts @@ -0,0 +1,141 @@ +/** + * 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 + */ + +import type * as React from 'react'; + +export type MeasureOnSuccessCallback = ( + x: number, + y: number, + width: number, + height: number, + pageX: number, + pageY: number, +) => void; + +export type MeasureInWindowOnSuccessCallback = ( + x: number, + y: number, + width: number, + height: number, +) => void; + +export type MeasureLayoutOnSuccessCallback = ( + left: number, + top: number, + width: number, + height: number, +) => void; + +/** + * NativeMethods provides methods to access the underlying native component directly. + * This can be useful in cases when you want to focus a view or measure its on-screen dimensions, + * for example. + * The methods described here are available on most of the default components provided by React Native. + * Note, however, that they are not available on composite components that aren't directly backed by a + * native view. This will generally include most components that you define in your own app. + * For more information, see [Direct Manipulation](https://reactnative.dev/docs/direct-manipulation). + * @see https://github.com/facebook/react-native/blob/master/Libraries/Renderer/shims/ReactNativeTypes.js#L87 + */ +export interface NativeMethods { + /** + * Determines the location on screen, width, and height of the given view and + * returns the values via an async callback. If successful, the callback will + * be called with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * Note that these measurements are not available until after the rendering + * has been completed in native. If you need the measurements as soon as + * possible, consider using the [`onLayout` + * prop](docs/view.html#onlayout) instead. + */ + measure(callback: MeasureOnSuccessCallback): void; + + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow(callback: MeasureInWindowOnSuccessCallback): void; + + /** + * Like [`measure()`](#measure), but measures the view relative an ancestor, + * specified as `relativeToNativeComponentRef`. This means that the returned x, y + * are relative to the origin x, y of the ancestor view. + * _Can also be called with a relativeNativeNodeHandle but is deprecated._ + */ + measureLayout( + relativeToNativeComponentRef: HostComponent | number, + onSuccess: MeasureLayoutOnSuccessCallback, + onFail: () => void /* currently unused */, + ): void; + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](https://reactnative.dev/docs/direct-manipulation)). + */ + setNativeProps(nativeProps: object): void; + + /** + * Requests focus for the given input or view. The exact behavior triggered + * will depend on the platform and type of view. + */ + focus(): void; + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur(): void; + + refs: { + [key: string]: React.Component; + }; +} + +/** + * @deprecated Use NativeMethods instead. + */ +export type NativeMethodsMixin = NativeMethods; +/** + * @deprecated Use NativeMethods instead. + */ +export type NativeMethodsMixinType = NativeMethods; + +/** + * Represents a native component, such as those returned from `requireNativeComponent`. + * + * @see https://github.com/facebook/react-native/blob/v0.62.0-rc.5/Libraries/Renderer/shims/ReactNativeTypes.js + * + * @todo This should eventually be defined as an AbstractComponent, but that + * should first be introduced in the React typings. + */ +export interface HostComponent

+ extends Pick< + React.ComponentClass

, + Exclude, 'new'> + > { + new (props: P, context?: any): React.Component

& Readonly; +}