|
| 1 | +/** |
| 2 | + * Copyright (c) Meta Platforms, Inc. and affiliates. |
| 3 | + * |
| 4 | + * This source code is licensed under the MIT license found in the |
| 5 | + * LICENSE file in the root directory of this source tree. |
| 6 | + * |
| 7 | + * @format |
| 8 | + */ |
| 9 | + |
| 10 | +import {GestureResponderEvent} from '../../Types/CoreEventTypes'; |
| 11 | + |
| 12 | +/** |
| 13 | + * Gesture recognition on mobile devices is much more complicated than web. |
| 14 | + * A touch can go through several phases as the app determines what the user's intention is. |
| 15 | + * For example, the app needs to determine if the touch is scrolling, sliding on a widget, or tapping. |
| 16 | + * This can even change during the duration of a touch. There can also be multiple simultaneous touches. |
| 17 | + * |
| 18 | + * The touch responder system is needed to allow components to negotiate these touch interactions |
| 19 | + * without any additional knowledge about their parent or child components. |
| 20 | + * This system is implemented in ResponderEventPlugin.js, which contains further details and documentation. |
| 21 | + * |
| 22 | + * Best Practices |
| 23 | + * Users can feel huge differences in the usability of web apps vs. native, and this is one of the big causes. |
| 24 | + * Every action should have the following attributes: |
| 25 | + * Feedback/highlighting- show the user what is handling their touch, and what will happen when they release the gesture |
| 26 | + * Cancel-ability- when making an action, the user should be able to abort it mid-touch by dragging their finger away |
| 27 | + * |
| 28 | + * These features make users more comfortable while using an app, |
| 29 | + * because it allows people to experiment and interact without fear of making mistakes. |
| 30 | + * |
| 31 | + * TouchableHighlight and Touchable* |
| 32 | + * The responder system can be complicated to use. |
| 33 | + * So we have provided an abstract Touchable implementation for things that should be "tappable". |
| 34 | + * This uses the responder system and allows you to easily configure tap interactions declaratively. |
| 35 | + * Use TouchableHighlight anywhere where you would use a button or link on web. |
| 36 | + */ |
| 37 | +export interface GestureResponderHandlers { |
| 38 | + /** |
| 39 | + * A view can become the touch responder by implementing the correct negotiation methods. |
| 40 | + * There are two methods to ask the view if it wants to become responder: |
| 41 | + */ |
| 42 | + |
| 43 | + /** |
| 44 | + * Does this view want to become responder on the start of a touch? |
| 45 | + */ |
| 46 | + onStartShouldSetResponder?: |
| 47 | + | ((event: GestureResponderEvent) => boolean) |
| 48 | + | undefined; |
| 49 | + |
| 50 | + /** |
| 51 | + * Called for every touch move on the View when it is not the responder: does this view want to "claim" touch responsiveness? |
| 52 | + */ |
| 53 | + onMoveShouldSetResponder?: |
| 54 | + | ((event: GestureResponderEvent) => boolean) |
| 55 | + | undefined; |
| 56 | + |
| 57 | + /** |
| 58 | + * If the View returns true and attempts to become the responder, one of the following will happen: |
| 59 | + */ |
| 60 | + |
| 61 | + onResponderEnd?: ((event: GestureResponderEvent) => void) | undefined; |
| 62 | + |
| 63 | + /** |
| 64 | + * The View is now responding for touch events. |
| 65 | + * This is the time to highlight and show the user what is happening |
| 66 | + */ |
| 67 | + onResponderGrant?: ((event: GestureResponderEvent) => void) | undefined; |
| 68 | + |
| 69 | + /** |
| 70 | + * Something else is the responder right now and will not release it |
| 71 | + */ |
| 72 | + onResponderReject?: ((event: GestureResponderEvent) => void) | undefined; |
| 73 | + |
| 74 | + /** |
| 75 | + * If the view is responding, the following handlers can be called: |
| 76 | + */ |
| 77 | + |
| 78 | + /** |
| 79 | + * The user is moving their finger |
| 80 | + */ |
| 81 | + onResponderMove?: ((event: GestureResponderEvent) => void) | undefined; |
| 82 | + |
| 83 | + /** |
| 84 | + * Fired at the end of the touch, ie "touchUp" |
| 85 | + */ |
| 86 | + onResponderRelease?: ((event: GestureResponderEvent) => void) | undefined; |
| 87 | + |
| 88 | + onResponderStart?: ((event: GestureResponderEvent) => void) | undefined; |
| 89 | + |
| 90 | + /** |
| 91 | + * Something else wants to become responder. |
| 92 | + * Should this view release the responder? Returning true allows release |
| 93 | + */ |
| 94 | + onResponderTerminationRequest?: |
| 95 | + | ((event: GestureResponderEvent) => boolean) |
| 96 | + | undefined; |
| 97 | + |
| 98 | + /** |
| 99 | + * The responder has been taken from the View. |
| 100 | + * Might be taken by other views after a call to onResponderTerminationRequest, |
| 101 | + * or might be taken by the OS without asking (happens with control center/ notification center on iOS) |
| 102 | + */ |
| 103 | + onResponderTerminate?: ((event: GestureResponderEvent) => void) | undefined; |
| 104 | + |
| 105 | + /** |
| 106 | + * onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, |
| 107 | + * where the deepest node is called first. |
| 108 | + * That means that the deepest component will become responder when multiple Views return true for *ShouldSetResponder handlers. |
| 109 | + * This is desirable in most cases, because it makes sure all controls and buttons are usable. |
| 110 | + * |
| 111 | + * However, sometimes a parent will want to make sure that it becomes responder. |
| 112 | + * This can be handled by using the capture phase. |
| 113 | + * Before the responder system bubbles up from the deepest component, |
| 114 | + * it will do a capture phase, firing on*ShouldSetResponderCapture. |
| 115 | + * So if a parent View wants to prevent the child from becoming responder on a touch start, |
| 116 | + * it should have a onStartShouldSetResponderCapture handler which returns true. |
| 117 | + */ |
| 118 | + onStartShouldSetResponderCapture?: |
| 119 | + | ((event: GestureResponderEvent) => boolean) |
| 120 | + | undefined; |
| 121 | + |
| 122 | + /** |
| 123 | + * onStartShouldSetResponder and onMoveShouldSetResponder are called with a bubbling pattern, |
| 124 | + * where the deepest node is called first. |
| 125 | + * That means that the deepest component will become responder when multiple Views return true for *ShouldSetResponder handlers. |
| 126 | + * This is desirable in most cases, because it makes sure all controls and buttons are usable. |
| 127 | + * |
| 128 | + * However, sometimes a parent will want to make sure that it becomes responder. |
| 129 | + * This can be handled by using the capture phase. |
| 130 | + * Before the responder system bubbles up from the deepest component, |
| 131 | + * it will do a capture phase, firing on*ShouldSetResponderCapture. |
| 132 | + * So if a parent View wants to prevent the child from becoming responder on a touch start, |
| 133 | + * it should have a onStartShouldSetResponderCapture handler which returns true. |
| 134 | + */ |
| 135 | + onMoveShouldSetResponderCapture?: |
| 136 | + | ((event: GestureResponderEvent) => boolean) |
| 137 | + | undefined; |
| 138 | +} |
| 139 | + |
| 140 | +/** |
| 141 | + * React Native also implements unstable_batchedUpdates |
| 142 | + */ |
| 143 | +export function unstable_batchedUpdates<A, B>( |
| 144 | + callback: (a: A, b: B) => any, |
| 145 | + a: A, |
| 146 | + b: B, |
| 147 | +): void; |
| 148 | +export function unstable_batchedUpdates<A>(callback: (a: A) => any, a: A): void; |
| 149 | +export function unstable_batchedUpdates(callback: () => any): void; |
0 commit comments