Skip to content

Add focus/blur example to RNTester #51634

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet';
import {TextStyle} from '../../StyleSheet/StyleSheetTypes';
import {
BlurEvent,
FocusEvent,
NativeSyntheticEvent,
NativeTouchEvent,
TargetedEvent,
Expand Down Expand Up @@ -455,7 +457,7 @@ export interface TextInputAndroidProps {
}

/**
* @deprecated Use `TextInputFocusEvent` instead
* @deprecated Use `FocusEvent` instead
*/
export interface TextInputFocusEventData extends TargetedEvent {
text: string;
Expand All @@ -464,6 +466,7 @@ export interface TextInputFocusEventData extends TargetedEvent {

/**
* @see TextInputProps.onFocus
* @deprecated Use `FocusEvent` instead
*/
export type TextInputFocusEvent = NativeSyntheticEvent<TextInputFocusEventData>;

Expand Down Expand Up @@ -809,8 +812,11 @@ export interface TextInputProps

/**
* Callback that is called when the text input is blurred
*
* Note: If you are trying to find the last value of TextInput, you can use the `onEndEditing`
* event, which is fired upon completion of editing.
*/
onBlur?: ((e: TextInputFocusEvent) => void) | undefined;
onBlur?: ((e: BlurEvent) => void) | undefined;

/**
* Callback that is called when the text input's text changes.
Expand Down Expand Up @@ -859,7 +865,7 @@ export interface TextInputProps
/**
* Callback that is called when the text input is focused
*/
onFocus?: ((e: TextInputFocusEvent) => void) | undefined;
onFocus?: ((e: FocusEvent) => void) | undefined;

/**
* Callback that is called when the text input selection is changed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import type {HostInstance} from '../../../src/private/types/HostInstance';
import type {
BlurEvent,
FocusEvent,
GestureResponderEvent,
NativeSyntheticEvent,
ScrollEvent,
Expand Down Expand Up @@ -58,22 +60,22 @@ type TextInputContentSizeChangeEventData = $ReadOnly<{
export type TextInputContentSizeChangeEvent =
NativeSyntheticEvent<TextInputContentSizeChangeEventData>;

type TargetEvent = $ReadOnly<{
target: number,
...
}>;

type TextInputFocusEventData = TargetEvent;

/**
* @see TextInputProps.onBlur
* @deprecated Use `BlurEvent` instead.
*/
export type TextInputBlurEvent = NativeSyntheticEvent<TextInputFocusEventData>;
export type TextInputBlurEvent = BlurEvent;

/**
* @see TextInputProps.onFocus
* @deprecated Use `FocusEvent` instead.
*/
export type TextInputFocusEvent = NativeSyntheticEvent<TextInputFocusEventData>;
export type TextInputFocusEvent = FocusEvent;

type TargetEvent = $ReadOnly<{
target: number,
...
}>;

export type Selection = $ReadOnly<{
start: number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import type {HostInstance} from '../../../src/private/types/HostInstance';
import type {____TextStyle_Internal as TextStyleInternal} from '../../StyleSheet/StyleSheetTypes';
import type {
BlurEvent,
FocusEvent,
GestureResponderEvent,
ScrollEvent,
} from '../../Types/CoreEventTypes';
Expand Down Expand Up @@ -86,10 +88,12 @@ if (Platform.OS === 'android') {

export type {
AutoCapitalize,
BlurEvent,
EnterKeyHintType,
EnterKeyHintTypeAndroid,
EnterKeyHintTypeIOS,
EnterKeyHintTypeOptions,
FocusEvent,
InputModeOptions,
KeyboardType,
KeyboardTypeAndroid,
Expand Down Expand Up @@ -520,14 +524,14 @@ function InternalTextInput(props: TextInputProps): React.Node {
});
};

const _onFocus = (event: TextInputFocusEvent) => {
const _onFocus = (event: FocusEvent) => {
TextInputState.focusInput(inputRef.current);
if (props.onFocus) {
props.onFocus(event);
}
};

const _onBlur = (event: TextInputBlurEvent) => {
const _onBlur = (event: BlurEvent) => {
TextInputState.blurInput(inputRef.current);
if (props.onBlur) {
props.onBlur(event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import {Insets} from '../../../types/public/Insets';
import {GestureResponderHandlers} from '../../../types/public/ReactNativeRenderer';
import {StyleProp} from '../../StyleSheet/StyleSheet';
import {ViewStyle} from '../../StyleSheet/StyleSheetTypes';
import {LayoutChangeEvent, PointerEvents} from '../../Types/CoreEventTypes';
import {
BlurEvent,
FocusEvent,
LayoutChangeEvent,
PointerEvents,
} from '../../Types/CoreEventTypes';
import {Touchable} from '../Touchable/Touchable';
import {AccessibilityProps} from './ViewAccessibility';

Expand Down Expand Up @@ -76,6 +81,20 @@ export interface ViewPropsIOS extends TVViewPropsIOS {
}

export interface ViewPropsAndroid {
/**
* Callback that is called when the view is blurred.
*
* Note: This will only be called if the view is focusable.
*/
onBlur?: ((e: BlurEvent) => void) | null | undefined;

/**
* Callback that is called when the view is focused.
*
* Note: This will only be called if the view is focusable.
*/
onFocus?: ((e: FocusEvent) => void) | null | undefined;

/**
* Whether this view should render itself (and all of its children) into a single hardware texture on the GPU.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ const bubblingEventTypes = {
bubbled: 'onClick',
},
},
topBlur: {
phasedRegistrationNames: {
captured: 'onBlurCapture',
bubbled: 'onBlur',
},
},
topFocus: {
phasedRegistrationNames: {
captured: 'onFocusCapture',
bubbled: 'onFocus',
},
},
};

const directEventTypes = {
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native/Libraries/Types/CoreEventTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ export interface TargetedEvent {
target: number;
}

export type BlurEvent = NativeSyntheticEvent<TargetedEvent>;

export type FocusEvent = NativeSyntheticEvent<TargetedEvent>;

export interface PointerEvents {
onPointerEnter?: ((event: PointerEvent) => void) | undefined;
onPointerEnterCapture?: ((event: PointerEvent) => void) | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2672,13 +2672,12 @@ type TextInputContentSizeChangeEventData = $ReadOnly<{
}>;
export type TextInputContentSizeChangeEvent =
NativeSyntheticEvent<TextInputContentSizeChangeEventData>;
export type TextInputBlurEvent = BlurEvent;
export type TextInputFocusEvent = FocusEvent;
type TargetEvent = $ReadOnly<{
target: number,
...
}>;
type TextInputFocusEventData = TargetEvent;
export type TextInputBlurEvent = NativeSyntheticEvent<TextInputFocusEventData>;
export type TextInputFocusEvent = NativeSyntheticEvent<TextInputFocusEventData>;
export type Selection = $ReadOnly<{
start: number,
end: number,
Expand Down Expand Up @@ -3010,10 +3009,12 @@ export type TextInputType = InternalTextInput & TextInputComponentStatics;
exports[`public API should not change unintentionally Libraries/Components/TextInput/TextInput.js 1`] = `
"export type {
AutoCapitalize,
BlurEvent,
EnterKeyHintType,
EnterKeyHintTypeAndroid,
EnterKeyHintTypeIOS,
EnterKeyHintTypeOptions,
FocusEvent,
InputModeOptions,
KeyboardType,
KeyboardTypeAndroid,
Expand Down
3 changes: 3 additions & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -6777,9 +6777,12 @@ public class com/facebook/react/views/view/ReactViewManager : com/facebook/react
public static final field Companion Lcom/facebook/react/views/view/ReactViewManager$Companion;
public static final field REACT_CLASS Ljava/lang/String;
public fun <init> ()V
public synthetic fun addEventEmitters (Lcom/facebook/react/uimanager/ThemedReactContext;Landroid/view/View;)V
protected fun addEventEmitters (Lcom/facebook/react/uimanager/ThemedReactContext;Lcom/facebook/react/views/view/ReactViewGroup;)V
public synthetic fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Landroid/view/View;
public fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Lcom/facebook/react/views/view/ReactViewGroup;
public fun getCommandsMap ()Ljava/util/Map;
public fun getExportedCustomBubblingEventTypeConstants ()Ljava/util/Map;
public fun getName ()Ljava/lang/String;
public fun nextFocusDown (Lcom/facebook/react/views/view/ReactViewGroup;I)V
public fun nextFocusForward (Lcom/facebook/react/views/view/ReactViewGroup;I)V
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
*/

package com.facebook.react.uimanager.events

import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap

/** Represents a View losing focus */
internal class BlurEvent(surfaceId: Int, viewId: Int) : Event<BlurEvent>(surfaceId, viewId) {

override fun getEventName(): String = EVENT_NAME

override fun canCoalesce(): Boolean = false

protected override fun getEventData(): WritableMap {
return Arguments.createMap().apply { putInt("target", viewTag) }
}

internal companion object {
internal const val EVENT_NAME: String = "topBlur"
}
}
Original file line number Diff line number Diff line change
@@ -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.
*/

package com.facebook.react.uimanager.events

import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableMap

/** Represents a View gaining focus */
internal class FocusEvent(surfaceId: Int, viewId: Int) : Event<FocusEvent>(surfaceId, viewId) {

override fun getEventName(): String = EVENT_NAME

override fun canCoalesce(): Boolean = false

protected override fun getEventData(): WritableMap {
return Arguments.createMap().apply { putInt("target", viewTag) }
}

internal companion object {
internal const val EVENT_NAME: String = "topFocus"
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ import com.facebook.react.uimanager.ViewDefaults
import com.facebook.react.uimanager.ViewProps
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.uimanager.annotations.ReactPropGroup
import com.facebook.react.uimanager.events.BlurEvent
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.uimanager.events.FocusEvent
import com.facebook.react.uimanager.style.BorderRadiusProp
import com.facebook.react.uimanager.style.BorderStyle.Companion.fromString
import com.facebook.react.uimanager.style.LogicalEdge
Expand Down Expand Up @@ -896,9 +898,9 @@ public open class ReactTextInputManager public constructor() :
val surfaceId = reactContext.surfaceId
val eventDispatcher = getEventDispatcher(reactContext, editText)
if (hasFocus) {
eventDispatcher?.dispatchEvent(ReactTextInputFocusEvent(surfaceId, editText.id))
eventDispatcher?.dispatchEvent(FocusEvent(surfaceId, editText.id))
} else {
eventDispatcher?.dispatchEvent(ReactTextInputBlurEvent(surfaceId, editText.id))
eventDispatcher?.dispatchEvent(BlurEvent(surfaceId, editText.id))
eventDispatcher?.dispatchEvent(
ReactTextInputEndEditingEvent(surfaceId, editText.id, editText.text.toString()))
}
Expand Down
Loading