Skip to content

Commit fa0ffed

Browse files
huntiemeta-codesync[bot]
authored andcommitted
Align public type for Touchable
Summary: **Problem** Under the Strict TypeScript API, `Touchable` was a value-only TypeScript export referencing `TouchableImpl`, which leaked additional `{Mixin, renderDebugView}` members. **Fix** Export a declaration-merged `Touchable` type at root, specifying a public interface for this module that excludes these members. **Impact** - API snapshot cleanup: Hides internal `TouchableImpl` and `TouchableMixinImpl` details. - **Functional**: Removes `Touchable.renderDebugView()` from the public API. This is **non-breaking** as this type was not previously modelled under the manual TS types. - **Functional**: Fixes equivalence of `Touchable` when referenced as a type under Uniwind — which was a breaking change vs the manual TS types (extra props were leaked). https://github.com/uni-stack/uniwind/blob/6b498f2ada673d2b92915c79a703286078b953c2/packages/uniwind/types.d.ts#L40 **Notes** - As part of this change, other `Libraries/`/`*Impl` APIs were audited to check for similar internal API leaks. This is the only obvious instance. - Also simplify outdated doc comment (`Touchable` subtypes are intended for primary use and have separate docs pages). Changelog: [General][Fixed] - **Strict TypeScript API**: Export a public `Touchable` type object, reducing its API to match the previous manual types Differential Revision: D110483989
1 parent 2fb4f13 commit fa0ffed

3 files changed

Lines changed: 28 additions & 134 deletions

File tree

packages/react-native/Libraries/Components/Touchable/Touchable.js

Lines changed: 18 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@ import BoundingDimensions from './BoundingDimensions';
2424
import Position from './Position';
2525
import * as React from 'react';
2626

27+
// Declaration-merged with `TouchableImpl` under TypeScript - this type is the
28+
// public API for `Touchable`, hiding internal details.
29+
/**
30+
* Touch event handlers a host component emits as a touch point moves over it,
31+
* from first contact through release or cancellation.
32+
*
33+
* These fire for every touch at the DOM-like event layer, independent of the
34+
* responder system. For press interactions with visual feedback, prefer
35+
* {@link Pressable}.
36+
*/
37+
export type Touchable = Readonly<{
38+
onTouchCancel?: ?(e: GestureResponderEvent) => void,
39+
onTouchEnd?: ?(e: GestureResponderEvent) => void,
40+
onTouchEndCapture?: ?(e: GestureResponderEvent) => void,
41+
onTouchMove?: ?(e: GestureResponderEvent) => void,
42+
onTouchStart?: ?(e: GestureResponderEvent) => void,
43+
}>;
44+
2745
const extractSingleTouch = (nativeEvent: {
2846
readonly changedTouches: ReadonlyArray<GestureResponderEvent['nativeEvent']>,
2947
readonly force?: number,
@@ -879,90 +897,6 @@ const {
879897
TouchableMixinImpl.withoutDefaultFocusAndBlur =
880898
TouchableMixinWithoutDefaultFocusAndBlur;
881899

882-
/**
883-
* `Touchable`: Taps done right.
884-
*
885-
* You hook your `ResponderEventPlugin` events into `Touchable`. `Touchable`
886-
* will measure time/geometry and tells you when to give feedback to the user.
887-
*
888-
* ====================== Touchable Tutorial ===============================
889-
* The `Touchable` mixin helps you handle the "press" interaction. It analyzes
890-
* the geometry of elements, and observes when another responder (scroll view
891-
* etc) has stolen the touch lock. It notifies your component when it should
892-
* give feedback to the user. (bouncing/highlighting/unhighlighting).
893-
*
894-
* - When a touch was activated (typically you highlight)
895-
* - When a touch was deactivated (typically you unhighlight)
896-
* - When a touch was "pressed" - a touch ended while still within the geometry
897-
* of the element, and no other element (like scroller) has "stolen" touch
898-
* lock ("responder") (Typically you bounce the element).
899-
*
900-
* A good tap interaction isn't as simple as you might think. There should be a
901-
* slight delay before showing a highlight when starting a touch. If a
902-
* subsequent touch move exceeds the boundary of the element, it should
903-
* unhighlight, but if that same touch is brought back within the boundary, it
904-
* should rehighlight again. A touch can move in and out of that boundary
905-
* several times, each time toggling highlighting, but a "press" is only
906-
* triggered if that touch ends while within the element's boundary and no
907-
* scroller (or anything else) has stolen the lock on touches.
908-
*
909-
* To create a new type of component that handles interaction using the
910-
* `Touchable` mixin, do the following:
911-
*
912-
* - Initialize the `Touchable` state.
913-
*
914-
* getInitialState: function() {
915-
* return merge(this.touchableGetInitialState(), yourComponentState);
916-
* }
917-
*
918-
* - Choose the rendered component who's touches should start the interactive
919-
* sequence. On that rendered node, forward all `Touchable` responder
920-
* handlers. You can choose any rendered node you like. Choose a node whose
921-
* hit target you'd like to instigate the interaction sequence:
922-
*
923-
* // In render function:
924-
* return (
925-
* <View
926-
* onStartShouldSetResponder={this.touchableHandleStartShouldSetResponder}
927-
* onResponderTerminationRequest={this.touchableHandleResponderTerminationRequest}
928-
* onResponderGrant={this.touchableHandleResponderGrant}
929-
* onResponderMove={this.touchableHandleResponderMove}
930-
* onResponderRelease={this.touchableHandleResponderRelease}
931-
* onResponderTerminate={this.touchableHandleResponderTerminate}>
932-
* <View>
933-
* Even though the hit detection/interactions are triggered by the
934-
* wrapping (typically larger) node, we usually end up implementing
935-
* custom logic that highlights this inner one.
936-
* </View>
937-
* </View>
938-
* );
939-
*
940-
* - You may set up your own handlers for each of these events, so long as you
941-
* also invoke the `touchable*` handlers inside of your custom handler.
942-
*
943-
* - Implement the handlers on your component class in order to provide
944-
* feedback to the user. See documentation for each of these class methods
945-
* that you should implement.
946-
*
947-
* touchableHandlePress: function() {
948-
* this.performBounceAnimation(); // or whatever you want to do.
949-
* },
950-
* touchableHandleActivePressIn: function() {
951-
* this.beginHighlighting(...); // Whatever you like to convey activation
952-
* },
953-
* touchableHandleActivePressOut: function() {
954-
* this.endHighlighting(...); // Whatever you like to convey deactivation
955-
* },
956-
*
957-
* - There are more advanced methods you can implement (see documentation below):
958-
* touchableGetHighlightDelayMS: function() {
959-
* return 20;
960-
* }
961-
* // In practice, *always* use a predeclared constant (conserve memory).
962-
* touchableGetPressRectOffset: function() {
963-
* return {top: 20, left: 20, right: 20, bottom: 100};
964-
* }
965-
*/
966900
const TouchableImpl = {
967901
Mixin: TouchableMixinImpl,
968902
/**

packages/react-native/ReactNativeApi.d.ts

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<67eb674c33870c82986054f0cee48385>>
7+
* @generated SignedSource<<d7a5a7da19dfd641655a5e645b6bf1c0>>
88
*
99
* This file was generated by scripts/js-api/build-types/index.js.
1010
*/
@@ -399,16 +399,6 @@ declare const staggerImpl: (
399399
time: number,
400400
animations: Array<CompositeAnimation>,
401401
) => CompositeAnimation
402-
declare const States: {
403-
ERROR: "ERROR"
404-
NOT_RESPONDER: "NOT_RESPONDER"
405-
RESPONDER_ACTIVE_LONG_PRESS_IN: "RESPONDER_ACTIVE_LONG_PRESS_IN"
406-
RESPONDER_ACTIVE_LONG_PRESS_OUT: "RESPONDER_ACTIVE_LONG_PRESS_OUT"
407-
RESPONDER_ACTIVE_PRESS_IN: "RESPONDER_ACTIVE_PRESS_IN"
408-
RESPONDER_ACTIVE_PRESS_OUT: "RESPONDER_ACTIVE_PRESS_OUT"
409-
RESPONDER_INACTIVE_PRESS_IN: "RESPONDER_INACTIVE_PRESS_IN"
410-
RESPONDER_INACTIVE_PRESS_OUT: "RESPONDER_INACTIVE_PRESS_OUT"
411-
}
412402
declare const subtract: typeof $$AnimatedImplementation.subtract
413403
declare const subtractImpl: (
414404
a: AnimatedNode_default | number,
@@ -452,7 +442,6 @@ declare const ToastAndroid_default: {
452442
yOffset: number,
453443
) => void
454444
}
455-
declare const Touchable: typeof TouchableImpl_default
456445
declare const Touchable_default: (
457446
props: TouchableOpacityProps & {
458447
ref?: React.Ref<TouchableOpacityInstance>
@@ -464,33 +453,6 @@ declare const TouchableHighlight_default: (
464453
ref?: React.Ref<TouchableHighlightInstance>
465454
},
466455
) => React.ReactNode
467-
declare const TouchableImpl_default: {
468-
Mixin: typeof TouchableMixinImpl
469-
renderDebugView: ($$PARAM_0$$: {
470-
color: ColorValue
471-
hitSlop?: EdgeInsetsProp
472-
}) => null | React.ReactNode
473-
}
474-
declare const TouchableMixinImpl: {
475-
withoutDefaultFocusAndBlur: {}
476-
componentDidMount: () => void
477-
componentWillUnmount: () => void
478-
touchableGetInitialState: () => {
479-
touchable: {
480-
responderID: GestureResponderEvent["currentTarget"] | undefined
481-
touchState: TouchableState | undefined
482-
}
483-
}
484-
touchableHandleBlur: (e: BlurEvent) => void
485-
touchableHandleFocus: (e: FocusEvent) => void
486-
touchableHandleResponderGrant: (e: GestureResponderEvent) => void
487-
touchableHandleResponderMove: (e: GestureResponderEvent) => void
488-
touchableHandleResponderRelease: (e: GestureResponderEvent) => void
489-
touchableHandleResponderTerminate: (e: GestureResponderEvent) => void
490-
touchableHandleResponderTerminationRequest: () => any
491-
touchableHandleStartShouldSetResponder: () => any
492-
touchableLongPressCancelsPress: () => boolean
493-
}
494456
declare const TouchableOpacity: typeof Touchable_default
495457
declare const UIManager: typeof UIManager_default
496458
declare const UIManager_default: UIManagerJSInterface
@@ -5353,7 +5315,13 @@ declare type TimingAnimationConfig = Readonly<
53535315
}
53545316
>
53555317
declare type ToastAndroid = typeof ToastAndroid
5356-
declare type Touchable = typeof Touchable
5318+
declare type Touchable = {
5319+
readonly onTouchCancel?: (e: GestureResponderEvent) => void
5320+
readonly onTouchEnd?: (e: GestureResponderEvent) => void
5321+
readonly onTouchEndCapture?: (e: GestureResponderEvent) => void
5322+
readonly onTouchMove?: (e: GestureResponderEvent) => void
5323+
readonly onTouchStart?: (e: GestureResponderEvent) => void
5324+
}
53575325
declare type TouchableHighlight = typeof TouchableHighlight
53585326
declare type TouchableHighlightBaseProps = {
53595327
readonly activeOpacity?: number
@@ -5460,15 +5428,6 @@ declare type TouchableOpacityTVProps = {
54605428
readonly nextFocusRight?: number
54615429
readonly nextFocusUp?: number
54625430
}
5463-
declare type TouchableState =
5464-
| typeof States.ERROR
5465-
| typeof States.NOT_RESPONDER
5466-
| typeof States.RESPONDER_ACTIVE_LONG_PRESS_IN
5467-
| typeof States.RESPONDER_ACTIVE_LONG_PRESS_OUT
5468-
| typeof States.RESPONDER_ACTIVE_PRESS_IN
5469-
| typeof States.RESPONDER_ACTIVE_PRESS_OUT
5470-
| typeof States.RESPONDER_INACTIVE_PRESS_IN
5471-
| typeof States.RESPONDER_INACTIVE_PRESS_OUT
54725431
declare function TouchableWithoutFeedback(
54735432
props: TouchableWithoutFeedbackProps,
54745433
): React.ReactNode
@@ -6153,7 +6112,7 @@ export {
61536112
TextProps, // 58466ea1
61546113
TextStyle, // b62b8399
61556114
ToastAndroid, // 88a8969a
6156-
Touchable, // c15da0a2
6115+
Touchable, // f740327f
61576116
TouchableHighlight, // 20ba0199
61586117
TouchableHighlightInstance, // b510c0eb
61596118
TouchableHighlightProps, // 337a9164

packages/react-native/index.js.flow

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export type {
175175
} from './Libraries/Components/TextInput/TextInput';
176176
export {default as TextInput} from './Libraries/Components/TextInput/TextInput';
177177

178+
export type {Touchable} from './Libraries/Components/Touchable/Touchable';
178179
export {default as Touchable} from './Libraries/Components/Touchable/Touchable';
179180

180181
export type {

0 commit comments

Comments
 (0)