Skip to content

Commit

Permalink
KeyboardFocusTextInput: text input wrapper for standardize TextInput …
Browse files Browse the repository at this point in the history
…focusing behavior (#80)

* feat: add text input wrapper

* chore: update readme with example
  • Loading branch information
ArturKalach authored Jul 3, 2024
1 parent e383cc9 commit a2c7cde
Show file tree
Hide file tree
Showing 59 changed files with 941 additions and 397 deletions.
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

0 comments on commit a2c7cde

Please sign in to comment.