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.
Files changed (122) hide show
  1. package/README.md +37 -129
  2. package/android/src/main/java/com/externalkeyboard/ExternalKeyboardViewPackage.java +2 -0
  3. package/android/src/main/java/com/externalkeyboard/helper/FocusHelper.java +70 -0
  4. package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardLockView/ExternalKeyboardLockView.java +115 -0
  5. package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardLockView/ExternalKeyboardLockViewManager.java +32 -0
  6. package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardLockView/LockService.java +44 -0
  7. package/android/src/newarch/ExternalKeyboardLockViewManagerSpec.java +8 -0
  8. package/android/src/oldarch/ExternalKeyboardLockViewManagerSpec.java +12 -0
  9. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusGuideDelegate/RNCEKVFocusGuideDelegate.h +36 -0
  10. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusGuideDelegate/RNCEKVFocusGuideDelegate.mm +150 -0
  11. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.h +14 -0
  12. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.mm +98 -349
  13. package/ios/Extensions/RCTTextInputComponentView+RNCEKVExternalKeyboard.h +1 -1
  14. package/ios/Extensions/RCTTextInputComponentView+RNCEKVExternalKeyboard.mm +11 -3
  15. package/ios/Extensions/UIViewController+RNCEKVExternalKeyboard.h +1 -1
  16. package/ios/Extensions/UIViewController+RNCEKVExternalKeyboard.mm +17 -17
  17. package/ios/Helpers/RNCEKVFocusGuideHelper/RNCEKVFocusGuideHelper.h +32 -0
  18. package/ios/Helpers/RNCEKVFocusGuideHelper/RNCEKVFocusGuideHelper.mm +81 -0
  19. package/ios/Helpers/RNCEKVSwizzlingHelper/RNCEKVSwizzlingHelper.h +16 -0
  20. package/ios/Helpers/RNCEKVSwizzlingHelper/RNCEKVSwizzlingHelper.mm +27 -0
  21. package/ios/Modules/RNCEKVExternalKeyboardModule.mm +3 -3
  22. package/ios/Services/RNCEKVFocusLinkObserver.h +7 -1
  23. package/ios/Services/RNCEKVFocusLinkObserver.mm +31 -6
  24. package/ios/Services/RNCEKVKeyboardOrderManager/RNCEKVKeyboardOrderManager.h +17 -0
  25. package/ios/Services/RNCEKVKeyboardOrderManager/RNCEKVKeyboardOrderManager.mm +15 -0
  26. package/ios/Services/{RNCEKVRelashioship.h → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVOrderRelationship.h} +8 -7
  27. package/ios/Services/{RNCEKVRelashioship.mm → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVOrderRelationship.mm} +36 -13
  28. package/ios/Services/RNCEKVOrderLinking.h +2 -7
  29. package/ios/Services/RNCEKVOrderLinking.mm +27 -64
  30. package/ios/Services/RNCEKVOrderSubscriber.h +4 -3
  31. package/ios/Services/RNCEKVOrderSubscriber.mm +2 -1
  32. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockView.h +38 -0
  33. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockView.mm +62 -0
  34. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockViewManager.h +14 -0
  35. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockViewManager.mm +25 -0
  36. package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardView.mm +2 -2
  37. package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroup.mm +0 -1
  38. package/ios/Views/RNCEKVTextInputFocusWrapper/RNCEKVTextInputFocusWrapper.mm +1 -15
  39. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js +21 -0
  40. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js.map +1 -0
  41. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.js +11 -0
  42. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.js.map +1 -0
  43. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js +19 -0
  44. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js.map +1 -0
  45. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.js +15 -0
  46. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.js.map +1 -0
  47. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js +46 -0
  48. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js.map +1 -0
  49. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js +21 -0
  50. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js.map +1 -0
  51. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js +9 -0
  52. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js.map +1 -0
  53. package/lib/commonjs/context/FocusFrameProviderContext.js +28 -0
  54. package/lib/commonjs/context/FocusFrameProviderContext.js.map +1 -0
  55. package/lib/commonjs/index.js +7 -1
  56. package/lib/commonjs/index.js.map +1 -1
  57. package/lib/commonjs/nativeSpec/ExternalKeyboardLockViewNativeComponent.js +10 -0
  58. package/lib/commonjs/nativeSpec/ExternalKeyboardLockViewNativeComponent.js.map +1 -0
  59. package/lib/commonjs/types/KeyboardFocusLock.types.js +6 -0
  60. package/lib/commonjs/types/KeyboardFocusLock.types.js.map +1 -0
  61. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js +14 -0
  62. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js.map +1 -0
  63. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.js +4 -0
  64. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.js.map +1 -0
  65. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js +12 -0
  66. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js.map +1 -0
  67. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.js +8 -0
  68. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.js.map +1 -0
  69. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js +39 -0
  70. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js.map +1 -0
  71. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js +14 -0
  72. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js.map +1 -0
  73. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js +3 -0
  74. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js.map +1 -0
  75. package/lib/module/context/FocusFrameProviderContext.js +20 -0
  76. package/lib/module/context/FocusFrameProviderContext.js.map +1 -0
  77. package/lib/module/index.js +6 -0
  78. package/lib/module/index.js.map +1 -1
  79. package/lib/module/nativeSpec/ExternalKeyboardLockViewNativeComponent.js +3 -0
  80. package/lib/module/nativeSpec/ExternalKeyboardLockViewNativeComponent.js.map +1 -0
  81. package/lib/module/types/KeyboardFocusLock.types.js +2 -0
  82. package/lib/module/types/KeyboardFocusLock.types.js.map +1 -0
  83. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.d.ts +4 -0
  84. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.d.ts.map +1 -0
  85. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.d.ts +3 -0
  86. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.d.ts.map +1 -0
  87. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.d.ts +4 -0
  88. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.d.ts.map +1 -0
  89. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.d.ts +3 -0
  90. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.d.ts.map +1 -0
  91. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.d.ts +3 -0
  92. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.d.ts.map +1 -0
  93. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.d.ts +4 -0
  94. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.d.ts.map +1 -0
  95. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.d.ts +3 -0
  96. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.d.ts.map +1 -0
  97. package/lib/typescript/src/components/Touchable/Pressable.d.ts +1 -1
  98. package/lib/typescript/src/context/FocusFrameProviderContext.d.ts +12 -0
  99. package/lib/typescript/src/context/FocusFrameProviderContext.d.ts.map +1 -0
  100. package/lib/typescript/src/index.d.ts +4 -0
  101. package/lib/typescript/src/index.d.ts.map +1 -1
  102. package/lib/typescript/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.d.ts +9 -0
  103. package/lib/typescript/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.d.ts.map +1 -0
  104. package/lib/typescript/src/types/KeyboardFocusLock.types.d.ts +6 -0
  105. package/lib/typescript/src/types/KeyboardFocusLock.types.d.ts.map +1 -0
  106. package/lib/typescript/src/utils/withKeyboardFocus.d.ts +1 -1
  107. package/package.json +4 -3
  108. package/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.tsx +18 -0
  109. package/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.tsx +8 -0
  110. package/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.tsx +17 -0
  111. package/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.tsx +9 -0
  112. package/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.ts +40 -0
  113. package/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.tsx +16 -0
  114. package/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.tsx +5 -0
  115. package/src/context/FocusFrameProviderContext.tsx +36 -0
  116. package/src/index.tsx +8 -0
  117. package/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.ts +13 -0
  118. package/src/types/KeyboardFocusLock.types.ts +6 -0
  119. package/ios/Services/RNCEKVFocusLinkObserverManager.h +0 -23
  120. package/ios/Services/RNCEKVFocusLinkObserverManager.mm +0 -30
  121. /package/ios/Services/{RNCEKVSortedMap.h → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVSortedMap/RNCEKVSortedMap.h} +0 -0
  122. /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
- > [!NOTE]
9
- > React Native `0.80.0` (`0.79.0`) includes a fix for `TextInput` focus on Android.
10
- > `TextInput`: Can now focus TextInput with keyboard ([e00028f6bb](https://github.com/facebook/react-native/commit/e00028f6bb6c19de861f9a25f377295755f3671b) by [@joevilches](https://github.com/joevilches))
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
- You can find more examples here: [Focus Link Order](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusLinkOrder.tsx), [DPad Order](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusDPadOrder.tsx)
12
+ ## Features
61
13
 
62
- | Props | Description | Type |
63
- | :-- | :-- | :-- |
64
- | orderId? | A unique ID used for link target identification. | `string` |
65
- | orderBackward? | ID of the target for backward navigation with "Tab + Shift". | `string` |
66
- | orderForward? | ID of the target for forward navigation with "Tab". | `string` |
67
- | orderLeft? | ID of the target for navigation to the left. | `string` |
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
- ## Indexes Focus Order
21
+ ## New Release: Focus Lock
73
22
 
74
- Linking is one of the best ways to set up focus order. However, there may be cases where you need to define the order of multiple elements, such as groups. As an alternative solution, you can use Indexes.
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
- ```tsx
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
- ```tsx
103
- <Pressable
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
- | Props | Description | Type |
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
- You can find more examples here: [Focus Order via indexes](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusOrder.tsx)
37
+ The focus lock functionality should be used as a pair:
119
38
 
120
- ## Focus Lock
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
- Finally, you can lock focus to specific directions.
42
+ | Prop | Description |
43
+ | :-- | :-- |
44
+ | ViewProps | Includes all standard React Native View properties, such as style, testID, etc. |
123
45
 
124
46
  ```tsx
125
- <Pressable
126
- lockFocus={['down', 'right']}
127
- >
128
- <Text>Lock Example</Text>
129
- </Pressable>
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
+ }
@@ -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
+
@@ -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 */