Skip to content
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

KeyboardFocusTextInput: text input wrapper for standardize TextInput focusing behavior #80

Merged
merged 2 commits into from
Jul 3, 2024
Merged
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
165 changes: 104 additions & 61 deletions README.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions android/src/main/java/com/reactnativea11y/A11yPackage.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.module.model.ReactModuleInfo;
import com.reactnativea11y.components.RCA11yFocusWrapperManager;
import com.reactnativea11y.components.RCA11yTextInputWrapperManager;

public class A11yPackage extends TurboReactPackage {

Expand Down Expand Up @@ -50,6 +52,7 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() {
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
List<ViewManager> viewManagers = new ArrayList<>();
viewManagers.add(new RCA11yFocusWrapperManager());
viewManagers.add(new RCA11yTextInputWrapperManager());
return viewManagers;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.reactnativea11y;
package com.reactnativea11y.components;

import android.content.Context;
import android.util.AttributeSet;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.reactnativea11y;
package com.reactnativea11y.components;

import android.view.KeyEvent;
import android.view.View;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.reactnativea11y.components;


import android.content.Context;
import android.graphics.Rect;
import android.view.KeyEvent;
import android.view.View;

import com.facebook.react.views.textinput.ReactEditText;
import com.facebook.react.views.view.ReactViewGroup;

public class RCA11yTextInputWrapper extends ReactViewGroup {

public static final byte FOCUS_BY_PRESS = 1;
private ReactEditText reactEditText = null;

private int focusType = 0;

public RCA11yTextInputWrapper(Context context) {
super(context);
}

public void setEditText(ReactEditText editText) {
if (editText != null) {
this.reactEditText = editText;
} else {
this.reactEditText.setOnFocusChangeListener(null);
}
}

public void setFocusType(int focusType) {
this.focusType = focusType;
}

public void setBlurType(int blurType) {
// Stub, Android does not allow to type in EditField from another view. Even focus remains typing with soft or hard keyboard won't work
}


@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (focusType == FOCUS_BY_PRESS && keyCode == KeyEvent.KEYCODE_SPACE) {
this.handleTextInputFocus();
}
return super.onKeyDown(keyCode, event);
}

@Override
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
if ((direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) && focusType != FOCUS_BY_PRESS) {
this.handleTextInputFocus();
return true;
}

return super.requestFocus(direction, previouslyFocusedRect);
}

private void handleTextInputFocus() {
this.reactEditText.requestFocusFromJS();
this.setFocusable(false);

this.reactEditText.setOnFocusChangeListener((textInput, hasTextEditFocus) -> {
if (!hasTextEditFocus) {
this.setFocusable(true);
this.reactEditText.setFocusable(false);
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.reactnativea11y.components;

import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.common.MapBuilder;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.views.textinput.ReactEditText;

import com.facebook.react.views.view.ReactViewGroup;
import com.reactnativea11y.events.FocusChangeEvent;

import java.util.Map;

@ReactModule(name = RCA11yTextInputWrapperManager.NAME)
public class RCA11yTextInputWrapperManager extends com.reactnativea11y.RCA11yTextInputWrapperManagerSpec<RCA11yTextInputWrapper> {

public static final String NAME = "RCA11yTextInputWrapper";

@Override
public String getName() {
return NAME;
}

@Override
public RCA11yTextInputWrapper createViewInstance(ThemedReactContext context) {
return subscribeOnHierarchy(new RCA11yTextInputWrapper(context));
}

@Override
protected void addEventEmitters(final ThemedReactContext reactContext, ReactViewGroup viewGroup) {
viewGroup.setFocusable(true);
viewGroup.setOnFocusChangeListener(
(v, hasFocus) -> {
FocusChangeEvent event = new FocusChangeEvent(viewGroup.getId(), hasFocus);
UIManagerHelper.getEventDispatcherForReactTag(reactContext, v.getId()).dispatchEvent(event);
});
}

protected RCA11yTextInputWrapper subscribeOnHierarchy(RCA11yTextInputWrapper viewGroup) {
viewGroup.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override
public void onChildViewAdded(View parent, View child) {
if (child instanceof ReactEditText) {
viewGroup.setEditText((ReactEditText) child);
}
}

@Override
public void onChildViewRemoved(View parent, View child) {
if (child instanceof ReactEditText) {
viewGroup.setEditText(null);
}
}
});

return viewGroup;
}

@Nullable
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
Map<String, Object> export = MapBuilder.<String, Object>builder().build();
if (export == null) {
export = MapBuilder.newHashMap();
}

export.put(FocusChangeEvent.EVENT_NAME, MapBuilder.of("registrationName", "onFocusChange"));

return export;
}

@Override
@ReactProp(name = "focusType")
public void setFocusType(RCA11yTextInputWrapper view, int value) {
view.setFocusType(value);
}

@Override
@ReactProp(name = "blurType")
public void setBlurType(RCA11yTextInputWrapper view, int value) {
view.setBlurType(value);
}


@Override
@ReactProp(name = "canBeFocused", defaultBoolean = true)
public void setCanBeFocused(RCA11yTextInputWrapper view, boolean value) {
view.setFocusable(value);
}

@Override
public void onDropViewInstance(@NonNull ReactViewGroup viewGroup) {
if (viewGroup instanceof RCA11yTextInputWrapper) {
RCA11yTextInputWrapper wrapper = (RCA11yTextInputWrapper) viewGroup;
wrapper.setEditText(null);
wrapper.setOnFocusChangeListener(null);
}
super.onDropViewInstance(viewGroup);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import android.os.Build;
import android.view.KeyEvent;

import com.reactnativea11y.RCA11yFocusWrapper;

import java.util.HashMap;

public class KeyboardKeyPressHandler {
Expand Down
15 changes: 15 additions & 0 deletions android/src/newarch/RCA11yTextInputWrapperManagerSpec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.reactnativea11y;

import com.facebook.react.viewmanagers.RCA11yTextInputWrapperManagerInterface;
import com.facebook.react.views.view.ReactViewGroup;
import com.facebook.react.views.view.ReactViewManager;
import com.facebook.soloader.SoLoader;
import com.reactnativea11y.BuildConfig;

public abstract class RCA11yTextInputWrapperManagerSpec<T extends ReactViewGroup> extends ReactViewManager implements RCA11yTextInputWrapperManagerInterface<T> {
static {
if (BuildConfig.CODEGEN_MODULE_REGISTRATION != null) {
SoLoader.loadLibrary(BuildConfig.CODEGEN_MODULE_REGISTRATION);
}
}
}
13 changes: 13 additions & 0 deletions android/src/oldarch/RCA11yTextInputWrapperManagerSpec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.reactnativea11y;

import com.facebook.react.views.view.ReactViewGroup;
import com.facebook.react.views.view.ReactViewManager;
import com.reactnativea11y.components.RCA11yTextInputWrapper;

public abstract class RCA11yTextInputWrapperManagerSpec<T extends ReactViewGroup> extends ReactViewManager {
public abstract void setCanBeFocused(T wrapper, boolean canBeFocused);

public abstract void setFocusType(RCA11yTextInputWrapper view, int value);

public abstract void setBlurType(RCA11yTextInputWrapper view, int value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import android.app.Application;

import com.a11ynewarch.textinput.RCTEditTextPackage;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
Expand All @@ -26,7 +25,6 @@ public boolean getUseDeveloperSupport() {
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new RCTEditTextPackage());

return packages;
}
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions examples/A11yNewArch/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ PODS:
- React-jsinspector (0.71.6)
- React-logger (0.71.6):
- glog
- react-native-a11y (0.4.4):
- react-native-a11y (0.4.6):
- RCT-Folly
- RCTRequired
- RCTTypeSafety
Expand Down Expand Up @@ -1051,7 +1051,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: 7894956638ff3e00819dd3f9f6f4a84da38f2409
React-jsinspector: d5ce2ef3eb8fd30c28389d0bc577918c70821bd6
React-logger: 9332c3e7b4ef007a0211c0a9868253aac3e1da82
react-native-a11y: 95bb961c50da3093d511fd59aeaa076c32738fd6
react-native-a11y: e3493a8e3d6adaea2af466bd6803e425fe9adb08
react-native-safe-area-context: 0dfc8e3a7d5ff115d100bafe4269d64a2c0a1456
React-perflogger: 43392072a5b867a504e2b4857606f8fc5a403d7f
React-RCTActionSheet: c7b67c125bebeda9fb19fc7b200d85cb9d6899c4
Expand Down
Loading