react-native-external-keyboard 0.6.8 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -129
- package/android/src/main/java/com/externalkeyboard/ExternalKeyboardViewPackage.java +2 -0
- package/android/src/main/java/com/externalkeyboard/helper/FocusHelper.java +70 -0
- package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardLockView/ExternalKeyboardLockView.java +115 -0
- package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardLockView/ExternalKeyboardLockViewManager.java +32 -0
- package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardLockView/LockService.java +44 -0
- package/android/src/newarch/ExternalKeyboardLockViewManagerSpec.java +8 -0
- package/android/src/oldarch/ExternalKeyboardLockViewManagerSpec.java +12 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusGuideDelegate/RNCEKVFocusGuideDelegate.h +36 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusGuideDelegate/RNCEKVFocusGuideDelegate.mm +150 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.h +14 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.mm +98 -349
- package/ios/Extensions/RCTTextInputComponentView+RNCEKVExternalKeyboard.h +1 -1
- package/ios/Extensions/RCTTextInputComponentView+RNCEKVExternalKeyboard.mm +11 -3
- package/ios/Extensions/UIViewController+RNCEKVExternalKeyboard.h +1 -1
- package/ios/Extensions/UIViewController+RNCEKVExternalKeyboard.mm +17 -17
- package/ios/Helpers/RNCEKVFocusGuideHelper/RNCEKVFocusGuideHelper.h +32 -0
- package/ios/Helpers/RNCEKVFocusGuideHelper/RNCEKVFocusGuideHelper.mm +81 -0
- package/ios/Helpers/RNCEKVSwizzlingHelper/RNCEKVSwizzlingHelper.h +16 -0
- package/ios/Helpers/RNCEKVSwizzlingHelper/RNCEKVSwizzlingHelper.mm +27 -0
- package/ios/Modules/RNCEKVExternalKeyboardModule.mm +3 -3
- package/ios/Services/RNCEKVFocusLinkObserver.h +7 -1
- package/ios/Services/RNCEKVFocusLinkObserver.mm +31 -6
- package/ios/Services/RNCEKVKeyboardOrderManager/RNCEKVKeyboardOrderManager.h +17 -0
- package/ios/Services/RNCEKVKeyboardOrderManager/RNCEKVKeyboardOrderManager.mm +15 -0
- package/ios/Services/{RNCEKVRelashioship.h → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVOrderRelationship.h} +8 -7
- package/ios/Services/{RNCEKVRelashioship.mm → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVOrderRelationship.mm} +36 -13
- package/ios/Services/RNCEKVOrderLinking.h +2 -7
- package/ios/Services/RNCEKVOrderLinking.mm +27 -64
- package/ios/Services/RNCEKVOrderSubscriber.h +4 -3
- package/ios/Services/RNCEKVOrderSubscriber.mm +2 -1
- package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockView.h +38 -0
- package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockView.mm +62 -0
- package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockViewManager.h +14 -0
- package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockViewManager.mm +25 -0
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardView.mm +2 -2
- package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroup.mm +0 -1
- package/ios/Views/RNCEKVTextInputFocusWrapper/RNCEKVTextInputFocusWrapper.mm +1 -15
- package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js +21 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.js +11 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js +19 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.js +15 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js +46 -0
- package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js +21 -0
- package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js +9 -0
- package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js.map +1 -0
- package/lib/commonjs/context/FocusFrameProviderContext.js +28 -0
- package/lib/commonjs/context/FocusFrameProviderContext.js.map +1 -0
- package/lib/commonjs/index.js +7 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/nativeSpec/ExternalKeyboardLockViewNativeComponent.js +10 -0
- package/lib/commonjs/nativeSpec/ExternalKeyboardLockViewNativeComponent.js.map +1 -0
- package/lib/commonjs/types/KeyboardFocusLock.types.js +6 -0
- package/lib/commonjs/types/KeyboardFocusLock.types.js.map +1 -0
- package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js +14 -0
- package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js.map +1 -0
- package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.js +4 -0
- package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.js.map +1 -0
- package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js +12 -0
- package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js.map +1 -0
- package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.js +8 -0
- package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.js.map +1 -0
- package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js +39 -0
- package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js.map +1 -0
- package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js +14 -0
- package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js.map +1 -0
- package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js +3 -0
- package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js.map +1 -0
- package/lib/module/context/FocusFrameProviderContext.js +20 -0
- package/lib/module/context/FocusFrameProviderContext.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeSpec/ExternalKeyboardLockViewNativeComponent.js +3 -0
- package/lib/module/nativeSpec/ExternalKeyboardLockViewNativeComponent.js.map +1 -0
- package/lib/module/types/KeyboardFocusLock.types.js +2 -0
- package/lib/module/types/KeyboardFocusLock.types.js.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.d.ts +4 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.d.ts +3 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.d.ts +4 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.d.ts +3 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.d.ts +3 -0
- package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.d.ts +4 -0
- package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.d.ts +3 -0
- package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.d.ts.map +1 -0
- package/lib/typescript/src/components/Touchable/Pressable.d.ts +1 -1
- package/lib/typescript/src/context/FocusFrameProviderContext.d.ts +12 -0
- package/lib/typescript/src/context/FocusFrameProviderContext.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.d.ts +9 -0
- package/lib/typescript/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/types/KeyboardFocusLock.types.d.ts +6 -0
- package/lib/typescript/src/types/KeyboardFocusLock.types.d.ts.map +1 -0
- package/lib/typescript/src/utils/withKeyboardFocus.d.ts +1 -1
- package/package.json +4 -3
- package/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.tsx +18 -0
- package/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.tsx +8 -0
- package/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.tsx +17 -0
- package/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.tsx +9 -0
- package/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.ts +40 -0
- package/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.tsx +16 -0
- package/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.tsx +5 -0
- package/src/context/FocusFrameProviderContext.tsx +36 -0
- package/src/index.tsx +8 -0
- package/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.ts +13 -0
- package/src/types/KeyboardFocusLock.types.ts +6 -0
- package/ios/Services/RNCEKVFocusLinkObserverManager.h +0 -23
- package/ios/Services/RNCEKVFocusLinkObserverManager.mm +0 -30
- /package/ios/Services/{RNCEKVSortedMap.h → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVSortedMap/RNCEKVSortedMap.h} +0 -0
- /package/ios/Services/{RNCEKVSortedMap.mm → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVSortedMap/RNCEKVSortedMap.mm} +0 -0
package/README.md
CHANGED
|
@@ -5,152 +5,60 @@ React Native library for enhanced external keyboard support.
|
|
|
5
5
|
- ⚡️ The New Architecture is supported
|
|
6
6
|
- ⚡️ Bridgeless
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
>
|
|
12
|
-
> This means that there is no need to use the workaround with `KeyboardExtendedInput`, and it is recommended to use the default `TextInput` instead. Additionally, because of changes in `TextInput`, `focusType="press"` for `KeyboardExtendedInput` no longer works on Android.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## New Release: Focus Lock and Focus Order
|
|
16
|
-
Improved keyboard focus control with features like focus order, ordered links, and focus lock.
|
|
17
|
-
|
|
18
|
-
|Android| iOS|
|
|
19
|
-
|-|-|
|
|
20
|
-
| <image alt="Android Focus Order Example" src="https://github.com/user-attachments/assets/8bae353e-cf4b-41f7-8796-fd1cceae5df5" height="400" />| <image alt="iOS Focus Order Example" src="https://github.com/user-attachments/assets/51850cc6-9573-4ccb-b69c-14deefbb4b65" height="400"/> |
|
|
21
|
-
|
|
22
|
-
<details>
|
|
23
|
-
<summary>More Information</summary>
|
|
24
|
-
|
|
25
|
-
Advanced focus order functionality for Android and iOS, plus focus lock!
|
|
26
|
-
|
|
27
|
-
It can be really challenging to manage focus in React Native, but fortunately, there are tools available to simplify the process.
|
|
28
|
-
|
|
29
|
-
## Link Focus Order
|
|
30
|
-
|
|
31
|
-
`Linking` components could be the most logical way to define focus order. By using properties such as `orderId` and `orderBackward`, `orderForward`, `orderLeft`, `orderRight`, `orderUp`, and `orderDown`, you can customize the focus order according to your needs.
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
<View>
|
|
35
|
-
<Pressable
|
|
36
|
-
onPress={onPress}
|
|
37
|
-
orderId="0_0"
|
|
38
|
-
orderForward="0_2"
|
|
39
|
-
>
|
|
40
|
-
<Text>1</Text>
|
|
41
|
-
</Pressable>
|
|
42
|
-
<Pressable
|
|
43
|
-
onPress={onPress}
|
|
44
|
-
orderId="0_2"
|
|
45
|
-
orderBackward="0_1"
|
|
46
|
-
>
|
|
47
|
-
<Text>3</Text>
|
|
48
|
-
</Pressable>
|
|
49
|
-
<Pressable
|
|
50
|
-
onPress={onPress}
|
|
51
|
-
orderId="0_1"
|
|
52
|
-
orderForward="0_2"
|
|
53
|
-
orderBackward="0_0"
|
|
54
|
-
>
|
|
55
|
-
<Text>2</Text>
|
|
56
|
-
</Pressable>
|
|
57
|
-
</View>
|
|
58
|
-
```
|
|
8
|
+
iOS | Android
|
|
9
|
+
-- | --
|
|
10
|
+
<img src="/.github/images/rnek-ios-example.gif" height="500" /> | <img src="/.github/images/rnek-android-example.gif" height="500" />
|
|
59
11
|
|
|
60
|
-
|
|
12
|
+
## Features
|
|
61
13
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
| orderRight? | ID of the target for navigation to the right. | `string` |
|
|
69
|
-
| orderUp? | ID of the target for navigation upward. | `string` |
|
|
70
|
-
| orderDown? | ID of the target for navigation downward. | `string` |
|
|
14
|
+
- Keyboard focus management and autofocus capabilities.
|
|
15
|
+
- Key press event handling.
|
|
16
|
+
- Focus management for `TextInput` and `Pressable` components.
|
|
17
|
+
- Customization of the `Halo Effect` and `tintColor` for iOS.
|
|
18
|
+
- Keyboard focus order.
|
|
19
|
+
- Focus Lock.
|
|
71
20
|
|
|
72
|
-
##
|
|
21
|
+
## New Release: Focus Lock
|
|
73
22
|
|
|
74
|
-
|
|
23
|
+
| iOS | Android |
|
|
24
|
+
| :-- | :-- |
|
|
25
|
+
| <img src="/.github/images/rnek-focus-lock-ios.gif" height="500" /> | <img src="/.github/images/rnek-focus-lock-ios.gif" height="500" /> |
|
|
75
26
|
|
|
76
|
-
|
|
77
|
-
<KeyboardOrderFocusGroup>
|
|
78
|
-
<View>
|
|
79
|
-
<Pressable
|
|
80
|
-
onPress={onPress}
|
|
81
|
-
orderIndex={0}
|
|
82
|
-
>
|
|
83
|
-
<Text>First</Text>
|
|
84
|
-
</Pressable>
|
|
85
|
-
<Pressable
|
|
86
|
-
onPress={onPress}
|
|
87
|
-
orderIndex={2}
|
|
88
|
-
>
|
|
89
|
-
<Text>Third</Text>
|
|
90
|
-
</Pressable>
|
|
91
|
-
<Pressable
|
|
92
|
-
onPress={onPress}
|
|
93
|
-
orderIndex={1}
|
|
94
|
-
>
|
|
95
|
-
<Text>Second</Text>
|
|
96
|
-
</Pressable>
|
|
97
|
-
</View>
|
|
98
|
-
</KeyboardOrderFocusGroup>
|
|
99
|
-
```
|
|
100
|
-
Indexing requires `orderGroup` param for proper order set, you can use `KeyboardOrderFocusGroup` or provide `orderGroup` to the component.
|
|
27
|
+
> A new type of focus lock functionality has been introduced, featuring two new components: `Focus.Frame` and `Focus.Trap`. These components help manage and lock focus within specific areas of the screen.
|
|
101
28
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
orderGroup="main"
|
|
105
|
-
onPress={onPress}
|
|
106
|
-
orderIndex={2}
|
|
107
|
-
>
|
|
108
|
-
<Text>Back</Text>
|
|
109
|
-
</Pressable>
|
|
110
|
-
```
|
|
29
|
+
<details>
|
|
30
|
+
<summary>More Information</summary>
|
|
111
31
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
| orderGroup? | The name of the group containing ordered elements. | `string` |
|
|
115
|
-
| orderIndex? | The order index of the element within the group. | `number` |
|
|
32
|
+
- On iOS, `Focus.Trap` uses the native `accessibilityViewIsModal` property to keep the focus within a defined area.
|
|
33
|
+
- On Android, where no equivalent to `accessibilityViewIsModal` exists, custom logic has been implemented as a workaround. By default, Android uses a custom Activity or Modal to limit focus. While using a Modal is considered the best practice for focus locking on Android, some scenarios—such as issues with React Native's Modal or library-specific constraints—may require alternative implementations.
|
|
116
34
|
|
|
35
|
+
#### How It Works
|
|
117
36
|
|
|
118
|
-
|
|
37
|
+
The focus lock functionality should be used as a pair:
|
|
119
38
|
|
|
120
|
-
|
|
39
|
+
- `Focus.Frame`: This component is used at the root level of a "screen" to detect focus leaks and ensure that focus remains contained.
|
|
40
|
+
- `Focus.Trap`: This component wraps the content area where focus should be explicitly locked.
|
|
121
41
|
|
|
122
|
-
|
|
42
|
+
| Prop | Description |
|
|
43
|
+
| :-- | :-- |
|
|
44
|
+
| ViewProps | Includes all standard React Native View properties, such as style, testID, etc. |
|
|
123
45
|
|
|
124
46
|
```tsx
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
>
|
|
128
|
-
|
|
129
|
-
|
|
47
|
+
<Focus.Frame>
|
|
48
|
+
...
|
|
49
|
+
<Focus.Trap>
|
|
50
|
+
<Text accessibilityRole="header">Locked Area</Text>
|
|
51
|
+
<Button
|
|
52
|
+
title="Confirm"
|
|
53
|
+
accessibilityLabel="Confirm action"
|
|
54
|
+
/>
|
|
55
|
+
</Focus.Trap>
|
|
56
|
+
...
|
|
57
|
+
</Focus.Frame>
|
|
130
58
|
```
|
|
131
59
|
|
|
132
|
-
|
|
133
|
-
| Props | Description | Type |
|
|
134
|
-
| :-- | :-- | :-- |
|
|
135
|
-
| lockFocus? | An array of directions to lock focus. | Array of 'left' | 'right' | 'up' | 'down' | 'forward' | 'backward' | 'first' | 'last' |
|
|
136
|
-
|
|
137
|
-
> [!NOTE]
|
|
138
|
-
> `first` and `last` are specific to `iOS`. When focus is blocked for `forward` and `backward` on iOS, it checks for the `last` and `first` elements to focus.
|
|
139
60
|
</details>
|
|
140
61
|
|
|
141
|
-
|
|
142
|
-
iOS | Android
|
|
143
|
-
-- | --
|
|
144
|
-
<img src="/.github/images/rnek-ios-example.gif" height="500" /> | <img src="/.github/images/rnek-android-example.gif" height="500" />
|
|
145
|
-
|
|
146
|
-
## Features
|
|
147
|
-
|
|
148
|
-
- Keyboard focus management and autofocus capabilities.
|
|
149
|
-
- Key press event handling.
|
|
150
|
-
- Focus management for `TextInput` and `Pressable` components.
|
|
151
|
-
- Customization of the `Halo Effect` and `tintColor` for iOS.
|
|
152
|
-
- Keyboard focus order.
|
|
153
|
-
|
|
154
62
|
## Installation
|
|
155
63
|
|
|
156
64
|
```sh
|
|
@@ -2,6 +2,7 @@ package com.externalkeyboard;
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
import com.externalkeyboard.modules.ExternalKeyboardModule;
|
|
5
|
+
import com.externalkeyboard.views.ExternalKeyboardLockView.ExternalKeyboardLockViewManager;
|
|
5
6
|
import com.externalkeyboard.views.ExternalKeyboardView.ExternalKeyboardViewManager;
|
|
6
7
|
import com.externalkeyboard.views.KeyboardFocusGroup.KeyboardFocusGroupManager;
|
|
7
8
|
import com.externalkeyboard.views.TextInputFocusWrapper.TextInputFocusWrapperManager;
|
|
@@ -50,6 +51,7 @@ public class ExternalKeyboardViewPackage extends TurboReactPackage {
|
|
|
50
51
|
viewManagers.add(new ExternalKeyboardViewManager());
|
|
51
52
|
viewManagers.add(new TextInputFocusWrapperManager());
|
|
52
53
|
viewManagers.add(new KeyboardFocusGroupManager());
|
|
54
|
+
viewManagers.add(new ExternalKeyboardLockViewManager());
|
|
53
55
|
|
|
54
56
|
return viewManagers;
|
|
55
57
|
}
|
|
@@ -7,6 +7,9 @@ import android.view.ViewGroup;
|
|
|
7
7
|
import java.util.HashMap;
|
|
8
8
|
import java.util.Map;
|
|
9
9
|
|
|
10
|
+
import androidx.annotation.Nullable;
|
|
11
|
+
import androidx.core.view.ViewCompat;
|
|
12
|
+
|
|
10
13
|
public class FocusHelper {
|
|
11
14
|
private static final int MASK_FOCUS_UP = 0b1;
|
|
12
15
|
private static final int MASK_FOCUS_DOWN = 0b10;
|
|
@@ -60,4 +63,71 @@ public class FocusHelper {
|
|
|
60
63
|
|
|
61
64
|
return null;
|
|
62
65
|
}
|
|
66
|
+
public static boolean isAccessible(@Nullable View view) {
|
|
67
|
+
return view != null && ViewCompat.isImportantForAccessibility(view);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public static View findFirstAccessible(@Nullable ViewGroup viewGroup, boolean ignoreRoot) {
|
|
71
|
+
if (viewGroup == null) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!ignoreRoot && isAccessible(viewGroup)) {
|
|
76
|
+
return viewGroup;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
|
80
|
+
View child = viewGroup.getChildAt(i);
|
|
81
|
+
if (isAccessible(child)) {
|
|
82
|
+
return child;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (child instanceof ViewGroup) {
|
|
86
|
+
View accessibleChild = findFirstAccessible((ViewGroup) child, true);
|
|
87
|
+
if (accessibleChild != null) {
|
|
88
|
+
return accessibleChild;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public static View findFirstAccessible(@Nullable ViewGroup viewGroup) {
|
|
97
|
+
return findFirstAccessible(viewGroup, false);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public static View findFirstFocusable(@Nullable ViewGroup viewGroup, boolean ignoreRoot) {
|
|
101
|
+
if (viewGroup == null) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!ignoreRoot && isKeyboardFocusable(viewGroup)) {
|
|
106
|
+
return viewGroup;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (int i = 0; i < viewGroup.getChildCount(); i++) {
|
|
110
|
+
View child = viewGroup.getChildAt(i);
|
|
111
|
+
if (isKeyboardFocusable(child)) {
|
|
112
|
+
return child;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (child instanceof ViewGroup) {
|
|
116
|
+
View focusableChild = findFirstFocusable((ViewGroup) child, true);
|
|
117
|
+
if (focusableChild != null) {
|
|
118
|
+
return focusableChild;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public static View findFirstFocusable(@Nullable ViewGroup viewGroup) {
|
|
127
|
+
return findFirstFocusable(viewGroup, false);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private static boolean isKeyboardFocusable(View view) {
|
|
131
|
+
return view.isFocusable() && view.getVisibility() == View.VISIBLE && view.isEnabled();
|
|
132
|
+
}
|
|
63
133
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
package com.externalkeyboard.views.ExternalKeyboardLockView;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.view.View;
|
|
5
|
+
import android.view.ViewGroup;
|
|
6
|
+
import android.view.accessibility.AccessibilityEvent;
|
|
7
|
+
|
|
8
|
+
import com.externalkeyboard.helper.FocusHelper;
|
|
9
|
+
import com.facebook.react.views.view.ReactViewGroup;
|
|
10
|
+
|
|
11
|
+
public class ExternalKeyboardLockView extends ReactViewGroup {
|
|
12
|
+
private int componentType;
|
|
13
|
+
private Boolean lockDisable = false;
|
|
14
|
+
|
|
15
|
+
public ExternalKeyboardLockView(Context context) {
|
|
16
|
+
super(context);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static boolean isParentOf(ViewGroup parent, View child) {
|
|
20
|
+
View current = child;
|
|
21
|
+
while (current.getParent() instanceof View) {
|
|
22
|
+
current = (View) current.getParent();
|
|
23
|
+
if (current == parent) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public void setComponentType(int value) {
|
|
31
|
+
this.componentType = value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public void setLockDisabled(boolean lockDisabled) {
|
|
35
|
+
this.lockDisable = lockDisabled;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Override
|
|
39
|
+
public View focusSearch(View focused, int direction) {
|
|
40
|
+
try {
|
|
41
|
+
LockService lockService = LockService.getInstance();
|
|
42
|
+
|
|
43
|
+
if (componentType == 1) {
|
|
44
|
+
View keyboardView = lockService.getKeyboardView();
|
|
45
|
+
if (keyboardView != null && keyboardView != focused) {
|
|
46
|
+
return keyboardView;
|
|
47
|
+
}
|
|
48
|
+
return super.focusSearch(focused, direction);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (componentType == 0) {
|
|
52
|
+
View nextView = super.focusSearch(focused, direction);
|
|
53
|
+
View result = isParentOf(this, nextView) ? nextView : focused;
|
|
54
|
+
lockService.setKeyboardView(result);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return super.focusSearch(focused, direction);
|
|
59
|
+
} catch (Exception e) {
|
|
60
|
+
return focused;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@Override
|
|
65
|
+
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
|
|
66
|
+
if (this.lockDisable) {
|
|
67
|
+
return super.onRequestSendAccessibilityEvent(child, event);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {
|
|
71
|
+
return super.onRequestSendAccessibilityEvent(child, event);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
LockService lockService = LockService.getInstance();
|
|
75
|
+
|
|
76
|
+
if (componentType == 0) {
|
|
77
|
+
lockService.setView(child);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (componentType == 1) {
|
|
82
|
+
View storedView = lockService.getView();
|
|
83
|
+
if (storedView != null && storedView != child) {
|
|
84
|
+
storedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return super.onRequestSendAccessibilityEvent(child, event);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Override
|
|
93
|
+
protected void onAttachedToWindow() {
|
|
94
|
+
super.onAttachedToWindow();
|
|
95
|
+
this.post(this::focusFirstAccessible);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@Override
|
|
99
|
+
protected void onDetachedFromWindow() {
|
|
100
|
+
super.onDetachedFromWindow();
|
|
101
|
+
LockService.getInstance().clear();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private void focusFirstAccessible() {
|
|
105
|
+
View firstAccessible = FocusHelper.findFirstAccessible(this);
|
|
106
|
+
if (firstAccessible != null) {
|
|
107
|
+
firstAccessible.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
View firstFocusable = FocusHelper.findFirstFocusable(this);
|
|
111
|
+
if (firstFocusable != null) {
|
|
112
|
+
firstFocusable.requestFocus();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package com.externalkeyboard.views.ExternalKeyboardLockView;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.module.annotations.ReactModule;
|
|
4
|
+
import com.facebook.react.uimanager.ThemedReactContext;
|
|
5
|
+
import com.facebook.react.uimanager.annotations.ReactProp;
|
|
6
|
+
|
|
7
|
+
@ReactModule(name = ExternalKeyboardLockViewManager.NAME)
|
|
8
|
+
public class ExternalKeyboardLockViewManager extends com.externalkeyboard.ExternalKeyboardLockViewManagerSpec<ExternalKeyboardLockView> {
|
|
9
|
+
public static final String NAME = "ExternalKeyboardLockView";
|
|
10
|
+
|
|
11
|
+
@Override
|
|
12
|
+
public String getName() {
|
|
13
|
+
return NAME;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Override
|
|
17
|
+
public ExternalKeyboardLockView createViewInstance(ThemedReactContext context) {
|
|
18
|
+
return new ExternalKeyboardLockView(context);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Override
|
|
22
|
+
@ReactProp(name = "componentType")
|
|
23
|
+
public void setComponentType(ExternalKeyboardLockView view, int value) {
|
|
24
|
+
view.setComponentType(value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Override
|
|
28
|
+
@ReactProp(name = "lockDisabled")
|
|
29
|
+
public void setLockDisabled(ExternalKeyboardLockView view, boolean value) {
|
|
30
|
+
view.setLockDisabled(value);
|
|
31
|
+
}
|
|
32
|
+
}
|
package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardLockView/LockService.java
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package com.externalkeyboard.views.ExternalKeyboardLockView;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import java.lang.ref.WeakReference;
|
|
6
|
+
|
|
7
|
+
public class LockService {
|
|
8
|
+
private static LockService instance;
|
|
9
|
+
|
|
10
|
+
private WeakReference<View> viewRef;
|
|
11
|
+
private WeakReference<View> keyboardViewRef;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
private LockService() {
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static synchronized LockService getInstance() {
|
|
18
|
+
if (instance == null) {
|
|
19
|
+
instance = new LockService();
|
|
20
|
+
}
|
|
21
|
+
return instance;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public View getView() {
|
|
25
|
+
return viewRef != null ? viewRef.get() : null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public void setView(View view) {
|
|
29
|
+
viewRef = new WeakReference<>(view);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public View getKeyboardView() {
|
|
33
|
+
return keyboardViewRef != null ? keyboardViewRef.get() : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public void setKeyboardView(View view) {
|
|
37
|
+
keyboardViewRef = new WeakReference<>(view);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public void clear() {
|
|
41
|
+
this.viewRef = null;
|
|
42
|
+
this.keyboardViewRef = null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
package com.externalkeyboard;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.viewmanagers.ExternalKeyboardLockViewManagerInterface;
|
|
4
|
+
import com.facebook.react.views.view.ReactViewGroup;
|
|
5
|
+
import com.facebook.react.views.view.ReactViewManager;
|
|
6
|
+
|
|
7
|
+
public abstract class ExternalKeyboardLockViewManagerSpec<T extends ReactViewGroup> extends ReactViewManager implements ExternalKeyboardLockViewManagerInterface<T> {
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package com.externalkeyboard;
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import com.externalkeyboard.views.ExternalKeyboardLockView.ExternalKeyboardLockView;
|
|
5
|
+
import com.facebook.react.views.view.ReactViewManager;
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
public abstract class ExternalKeyboardLockViewManagerSpec<T extends ExternalKeyboardLockView> extends ReactViewManager {
|
|
9
|
+
public abstract void setComponentType(T view, int value);
|
|
10
|
+
public abstract void setLockDisabled(T view, boolean value);
|
|
11
|
+
}
|
|
12
|
+
|
package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusGuideDelegate/RNCEKVFocusGuideDelegate.h
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RNCEKVFocusGuideDelegate.h
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Artur Kalach on 16/07/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#ifndef RNCEKVFocusGuideDelegate_h
|
|
9
|
+
#define RNCEKVFocusGuideDelegate_h
|
|
10
|
+
|
|
11
|
+
#import <Foundation/Foundation.h>
|
|
12
|
+
#import "RNCEKVFocusOrderProtocol.h"
|
|
13
|
+
#import "RNCEKVFocusGuideHelper.h"
|
|
14
|
+
|
|
15
|
+
@interface RNCEKVFocusGuideDelegate : NSObject
|
|
16
|
+
|
|
17
|
+
- (instancetype _Nonnull)initWithView:(UIView<RNCEKVFocusOrderProtocol> *_Nonnull)view;
|
|
18
|
+
|
|
19
|
+
//- (void)setLeftGuide:(UIView *_Nullable)view;
|
|
20
|
+
//- (void)setRightGuide:(UIView *_Nullable)view;
|
|
21
|
+
//- (void)setUpGuide:(UIView *_Nullable)view;
|
|
22
|
+
//- (void)setDownGuide:(UIView *_Nullable)view;
|
|
23
|
+
//
|
|
24
|
+
//- (void)removeLeftGuide;
|
|
25
|
+
//- (void)removeRightGuide;
|
|
26
|
+
//- (void)removeUpGuide;
|
|
27
|
+
//- (void)removeDownGuide;
|
|
28
|
+
|
|
29
|
+
- (void)setIsFocused:(BOOL)value;
|
|
30
|
+
|
|
31
|
+
- (void)setGuideFor:(RNCEKVFocusGuideDirection)direction withView: (UIView *_Nonnull)view;
|
|
32
|
+
- (void)removeGuideFor:(RNCEKVFocusGuideDirection)direction;
|
|
33
|
+
|
|
34
|
+
@end
|
|
35
|
+
|
|
36
|
+
#endif /* RNCEKVFocusGuideDelegate_h */
|