Skip to content

Commit 163127b

Browse files
authored
Merge pull request #66 from ArturKalach/release/0.5.3
Release/0.5.3
2 parents 962128a + 8fffff6 commit 163127b

24 files changed

+355
-70
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ React Native library for enhanced external keyboard support.
1111
1212

1313
## New Release Features
14+
- Added `Keyboard.dismiss` functionality for Android.
1415
- Introduced an iOS-specific component: `KeyboardFocusGroup`, a component for managing the `tintColor`, `focusGroupIdentifier`, and group focus.
1516
- Enhanced `KeyboardExtendedBaseView` with `haloCornerRadius`, `haloExpandX`, and `haloExpandY` properties for customizing the appearance of the `Halo Effect`.
1617
- Enhanced `KeyboardExtendedBaseView` with `onBubbledContextMenuPress`, key press functionality has been also enhanced. Key presses can be listened to for a group of components, screens, or pages.
@@ -249,6 +250,18 @@ onFocus?: | Handler called when the component is focused  | `() => void`
249250
onBlur?: | Handler called when the component loses focus | `() => void`
250251
groupIdentifier?: | Relates to iOS `focusGroupIdentifier`: the identifier of the focus group to which this view belongs| `string`
251252

253+
### Keyboard
254+
Keyboard module to support soft keyboard dismissal.
255+
256+
```tsx
257+
import { Keyboard } from 'react-native-external-keyboard';
258+
259+
...
260+
Keyboard.dismiss();
261+
...
262+
```
263+
264+
This is needed for hiding the soft keyboard using a hardware keyboard. Additionally, the soft keyboard can be hidden from the settings or by pressing `Alt + K`.
252265

253266
# Migration 0.3.x to 0.4.0
254267

Original file line numberDiff line numberDiff line change
@@ -1,18 +1,49 @@
11
package com.externalkeyboard;
22

33

4+
import com.externalkeyboard.modules.ExternalKeyboardModule;
45
import com.externalkeyboard.views.ExternalKeyboardView.ExternalKeyboardViewManager;
56
import com.externalkeyboard.views.KeyboardFocusGroup.KeyboardFocusGroupManager;
67
import com.externalkeyboard.views.TextInputFocusWrapper.TextInputFocusWrapperManager;
7-
import com.facebook.react.ReactPackage;
8+
import com.facebook.react.BaseReactPackage;
9+
import com.facebook.react.TurboReactPackage;
810
import com.facebook.react.bridge.NativeModule;
911
import com.facebook.react.bridge.ReactApplicationContext;
12+
import com.facebook.react.module.model.ReactModuleInfo;
13+
import com.facebook.react.module.model.ReactModuleInfoProvider;
1014
import com.facebook.react.uimanager.ViewManager;
1115

1216
import java.util.ArrayList;
1317
import java.util.List;
18+
import java.util.HashMap;
19+
import java.util.Map;
1420

15-
public class ExternalKeyboardViewPackage implements ReactPackage {
21+
public class ExternalKeyboardViewPackage extends TurboReactPackage {
22+
@Override
23+
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
24+
if (name.equals(ExternalKeyboardModule.NAME)) {
25+
return new ExternalKeyboardModule(reactContext);
26+
} else {
27+
return null;
28+
}
29+
}
30+
31+
@Override
32+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
33+
return () -> {
34+
Map<String, ReactModuleInfo> map = new HashMap<>();
35+
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
36+
map.put(ExternalKeyboardModule.NAME, new ReactModuleInfo(
37+
ExternalKeyboardModule.NAME, // name
38+
ExternalKeyboardModule.NAME, // className
39+
false, // canOverrideExistingModule
40+
false, // needsEagerInit
41+
false, // isCXXModule
42+
isTurboModule // isTurboModule
43+
));
44+
return map;
45+
};
46+
}
1647

1748
@Override
1849
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
@@ -24,8 +55,5 @@ public List<ViewManager> createViewManagers(ReactApplicationContext reactContext
2455
return viewManagers;
2556
}
2657

27-
@Override
28-
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
29-
return new ArrayList<>();
30-
}
58+
3159
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.externalkeyboard.modules;
2+
3+
import android.content.Context;
4+
import android.view.View;
5+
import android.view.inputmethod.InputMethodManager;
6+
7+
import com.externalkeyboard.ExternalKeyboardModuleSpec;
8+
import com.facebook.react.bridge.Promise;
9+
import com.facebook.react.bridge.ReactApplicationContext;
10+
import com.facebook.react.bridge.ReactMethod;
11+
12+
public class ExternalKeyboardModule extends ExternalKeyboardModuleSpec {
13+
public static final String NAME = "ExternalKeyboardModule";
14+
private static View focusedView = null;
15+
private final ReactApplicationContext context;
16+
17+
18+
private boolean dismiss() {
19+
if(focusedView == null) return false;
20+
try {
21+
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
22+
if (imm != null) {
23+
imm.hideSoftInputFromWindow(focusedView.getWindowToken(), 0);
24+
return true;
25+
}
26+
} catch (Exception ignored){}
27+
28+
return false;
29+
}
30+
31+
32+
public static void setFocusedTextInput (View _focusedView) {
33+
focusedView = _focusedView;
34+
}
35+
36+
public ExternalKeyboardModule(ReactApplicationContext reactContext) {
37+
super(reactContext);
38+
context = reactContext;
39+
}
40+
41+
@Override
42+
public String getName() {
43+
return NAME;
44+
}
45+
46+
@Override
47+
@ReactMethod
48+
public void dismissKeyboard(Promise promise) {
49+
boolean result = dismiss();
50+
promise.resolve(result);
51+
}
52+
}

android/src/main/java/com/externalkeyboard/views/TextInputFocusWrapper/TextInputFocusWrapper.java

+55-17
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
package com.externalkeyboard.views.TextInputFocusWrapper;
22

3+
import static androidx.core.content.ContextCompat.getSystemService;
4+
35
import android.content.Context;
46
import android.graphics.Rect;
57
import android.text.Editable;
8+
import android.util.Log;
9+
import android.view.FocusFinder;
610
import android.view.KeyEvent;
711
import android.view.View;
812
import android.view.ViewGroup;
13+
import android.view.inputmethod.InputMethodManager;
914
import android.widget.EditText;
1015

1116
import androidx.annotation.NonNull;
1217

1318
import com.externalkeyboard.events.EventHelper;
19+
import com.externalkeyboard.modules.ExternalKeyboardModule;
1420
import com.facebook.react.bridge.ReactContext;
1521
import com.facebook.react.views.textinput.ReactEditText;
22+
import com.facebook.react.views.textinput.ReactTextInputManager;
1623

1724
public class TextInputFocusWrapper extends ViewGroup implements View.OnFocusChangeListener {
1825
private final Context context;
@@ -23,6 +30,25 @@ public class TextInputFocusWrapper extends ViewGroup implements View.OnFocusChan
2330
private View.OnAttachStateChangeListener onAttachListener;
2431
private boolean blurOnSubmit = true;
2532
private boolean multiline = false;
33+
private boolean keyboardFocusable = true;
34+
private Integer planedDirection = null;
35+
private static View focusedView = null;
36+
public boolean getIsFocusByPress() {
37+
return focusType == FOCUS_BY_PRESS;
38+
}
39+
40+
public void setKeyboardFocusable (boolean canBeFocusable) {
41+
if(keyboardFocusable == canBeFocusable) {
42+
return;
43+
}
44+
45+
keyboardFocusable = canBeFocusable;
46+
47+
this.setFocusable(keyboardFocusable);
48+
if(this.reactEditText != null) {
49+
this.reactEditText.setFocusable(false);
50+
}
51+
}
2652

2753
private View.OnAttachStateChangeListener getOnAttachListener() {
2854
if (onAttachListener == null) {
@@ -59,6 +85,23 @@ public void setEditText(ReactEditText editText) {
5985
if (focusType == FOCUS_BY_PRESS) {
6086
this.reactEditText.setFocusable(false);
6187
}
88+
OnFocusChangeListener reactListener = this.reactEditText.getOnFocusChangeListener();
89+
this.reactEditText.setOnFocusChangeListener((textInput, hasTextEditFocus) -> {
90+
reactListener.onFocusChange(textInput, hasTextEditFocus);
91+
focusedView = textInput;
92+
this.focusEventIgnore = false;
93+
if (focusType != FOCUS_BY_PRESS || !hasTextEditFocus) {
94+
onFocusChange(textInput, hasTextEditFocus);
95+
}
96+
97+
if(hasTextEditFocus) {
98+
ExternalKeyboardModule.setFocusedTextInput(textInput);
99+
}
100+
if (!hasTextEditFocus) {
101+
this.setFocusable(true);
102+
this.reactEditText.setFocusable(false);
103+
}
104+
});
62105
onMultiplyBlurSubmitHandle();
63106
} else {
64107
this.clearEditText();
@@ -87,6 +130,10 @@ public void setBlurType(int blurType) {
87130
public TextInputFocusWrapper(Context context) {
88131
super(context);
89132
this.context = context;
133+
134+
if(keyboardFocusable) {
135+
setFocusable(true);
136+
}
90137
}
91138

92139
public void setBlurOnSubmit(boolean blurOnSubmit) {
@@ -109,17 +156,16 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
109156
return super.onKeyDown(keyCode, event);
110157
}
111158

112-
@Override
113159
public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
114160
if ((direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) && focusType != FOCUS_BY_PRESS) {
115-
this.handleTextInputFocus();
116-
return true;
161+
this.handleTextInputFocus();
162+
return true;
117163
}
118164

119165
return super.requestFocus(direction, previouslyFocusedRect);
120166
}
121167

122-
private void onMultiplyBlurSubmitHandle() {
168+
private void onMultiplyBlurSubmitHandle() {
123169
if(this.reactEditText == null) return;
124170
if(this.multiline) {
125171
this.reactEditText.setOnKeyListener(new View.OnKeyListener() {
@@ -144,20 +190,12 @@ public boolean onKey(View v, int keyCode, KeyEvent event) {
144190

145191
private void handleTextInputFocus() {
146192
this.focusEventIgnore = true;
147-
this.reactEditText.setOnFocusChangeListener((textInput, hasTextEditFocus) -> {
148-
this.focusEventIgnore = false;
149-
if (focusType != FOCUS_BY_PRESS || !hasTextEditFocus) {
150-
onFocusChange(textInput, hasTextEditFocus);
151-
}
152-
153-
if (!hasTextEditFocus) {
154-
this.setFocusable(true);
155-
this.reactEditText.setFocusable(false);
156-
}
157-
});
158-
this.reactEditText.setFocusable(true);
159-
this.reactEditText.requestFocusFromJS();
160193
this.setFocusable(false);
194+
this.reactEditText.setFocusable(true);
195+
196+
if(!this.reactEditText.hasFocus()) {
197+
this.reactEditText.requestFocusFromJS();
198+
}
161199
}
162200

163201
@Override

android/src/main/java/com/externalkeyboard/views/TextInputFocusWrapper/TextInputFocusWrapperManager.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88

99
import com.externalkeyboard.events.FocusChangeEvent;
1010
import com.externalkeyboard.events.MultiplyTextSubmit;
11+
import com.externalkeyboard.views.ExternalKeyboardView.ExternalKeyboardView;
12+
import com.facebook.react.bridge.ReadableArray;
1113
import com.facebook.react.common.MapBuilder;
1214
import com.facebook.react.module.annotations.ReactModule;
1315
import com.facebook.react.uimanager.ThemedReactContext;
1416
import com.facebook.react.uimanager.annotations.ReactProp;
1517
import com.facebook.react.views.textinput.ReactEditText;
18+
import com.facebook.react.views.view.ReactViewGroup;
1619

1720
import java.util.HashMap;
1821
import java.util.Map;
@@ -34,7 +37,6 @@ public TextInputFocusWrapper createViewInstance(ThemedReactContext context) {
3437

3538
@Override
3639
protected void addEventEmitters(final ThemedReactContext reactContext, TextInputFocusWrapper viewGroup) {
37-
viewGroup.setFocusable(true);
3840
viewGroup.subscribeOnFocus();
3941
}
4042

@@ -91,7 +93,7 @@ public void setGroupIdentifier(TextInputFocusWrapper view, @Nullable String valu
9193
@Override
9294
@ReactProp(name = "canBeFocused", defaultBoolean = true)
9395
public void setCanBeFocused(TextInputFocusWrapper view, boolean value) {
94-
view.setFocusable(value);
96+
view.setKeyboardFocusable(value);
9597
}
9698

9799
@Override
@@ -124,7 +126,7 @@ public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
124126

125127
export.put(FocusChangeEvent.EVENT_NAME, createEventMap("onFocusChange"));
126128
export.put(MultiplyTextSubmit.EVENT_NAME, createEventMap("onMultiplyTextSubmit"));
127-
129+
128130
return export;
129131
}
130132
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.externalkeyboard;
2+
3+
import com.facebook.react.bridge.ReactApplicationContext;
4+
5+
public abstract class ExternalKeyboardModuleSpec extends NativeExternalKeyboardModuleSpec {
6+
protected ExternalKeyboardModuleSpec(ReactApplicationContext context) {
7+
super(context);
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.externalkeyboard;
2+
3+
import com.facebook.react.bridge.Promise;
4+
import com.facebook.react.bridge.ReactApplicationContext;
5+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
6+
7+
public abstract class ExternalKeyboardModuleSpec extends ReactContextBaseJavaModule {
8+
protected ExternalKeyboardModuleSpec(ReactApplicationContext context) {
9+
super(context);
10+
}
11+
12+
public abstract void dismissKeyboard(Promise promise);
13+
}

example/android/app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ if (isNewArchitectureEnabled()) {
129129
def isWindows = System.getProperty('os.name').toLowerCase().contains('windows')
130130

131131
if (isWindows) {
132-
commandLine 'cmd', '/c', 'npx bob build --target codegen'
132+
commandLine 'cmd', '/c', 'npx bob build'
133133
} else {
134-
commandLine 'sh', '-c', 'npx bob build --target codegen'
134+
commandLine 'sh', '-c', 'npx bob build'
135135
}
136136
}
137137
preBuild.dependsOn invokeLibraryCodegen

example/ios/Podfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ target 'ExternalKeyboardExample' do
3232

3333

3434
pre_install do |installer|
35-
system("cd ../../ && npx bob build --target codegen")
35+
system("cd ../../ && npx bob build")
3636
end
3737

3838
post_install do |installer|

example/ios/Podfile.lock

+3-3
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,7 @@ PODS:
12421242
- ReactCommon/turbomodule/bridging
12431243
- ReactCommon/turbomodule/core
12441244
- Yoga
1245-
- react-native-external-keyboard (0.5.1):
1245+
- react-native-external-keyboard (0.5.3):
12461246
- DoubleConversion
12471247
- glog
12481248
- hermes-engine
@@ -1913,7 +1913,7 @@ SPEC CHECKSUMS:
19131913
React-logger: 697873f06b8ba436e3cddf28018ab4741e8071b6
19141914
React-Mapbuffer: c174e11bdea12dce07df8669d6c0dc97eb0c7706
19151915
React-microtasksnativemodule: 8a80099ad7391f4e13a48b12796d96680f120dc6
1916-
react-native-external-keyboard: cab5e7d0e6b274e1ba7b5f67bddc51629f8ad18c
1916+
react-native-external-keyboard: ff6129ab940e6bb571df873281511161d9580b40
19171917
react-native-safe-area-context: cbadf383376f589bb611c8ae0280c1d4b7b447e9
19181918
React-nativeconfig: f7ab6c152e780b99a8c17448f2d99cf5f69a2311
19191919
React-NativeModulesApple: 70600f7edfc2c2a01e39ab13a20fd59f4c60df0b
@@ -1947,6 +1947,6 @@ SPEC CHECKSUMS:
19471947
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
19481948
Yoga: fcc198acd4a55599b3468cfb6ebc526baff5f06e
19491949

1950-
PODFILE CHECKSUM: da3435fd0238a05043abf0fa88b420ba9ea4e965
1950+
PODFILE CHECKSUM: 60fd2791380dbcec1be1a39c520a7d54b593cb12
19511951

19521952
COCOAPODS: 1.15.2

0 commit comments

Comments
 (0)