react-native-external-keyboard 0.6.7 → 0.7.0-rc

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.

Potentially problematic release.


This version of react-native-external-keyboard might be problematic. Click here for more details.

Files changed (130) hide show
  1. package/README.md +38 -131
  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/RNCEKVFocusDelegate/RNCEKVFocusDelegate.mm +58 -21
  10. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusGuideDelegate/RNCEKVFocusGuideDelegate.h +36 -0
  11. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusGuideDelegate/RNCEKVFocusGuideDelegate.mm +150 -0
  12. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.h +14 -0
  13. package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.mm +98 -349
  14. package/ios/Extensions/RCTEnhancedScrollView+RNCEKVExternalKeyboard.mm +12 -2
  15. package/ios/Extensions/RCTTextInputComponentView+RNCEKVExternalKeyboard.h +1 -1
  16. package/ios/Extensions/RCTTextInputComponentView+RNCEKVExternalKeyboard.mm +11 -3
  17. package/ios/Extensions/UIViewController+RNCEKVExternalKeyboard.h +1 -1
  18. package/ios/Extensions/UIViewController+RNCEKVExternalKeyboard.mm +17 -17
  19. package/ios/Helpers/RNCEKVFocusGuideHelper/RNCEKVFocusGuideHelper.h +32 -0
  20. package/ios/Helpers/RNCEKVFocusGuideHelper/RNCEKVFocusGuideHelper.mm +81 -0
  21. package/ios/Helpers/RNCEKVSwizzlingHelper/RNCEKVSwizzlingHelper.h +16 -0
  22. package/ios/Helpers/RNCEKVSwizzlingHelper/RNCEKVSwizzlingHelper.mm +27 -0
  23. package/ios/Modules/RNCEKVExternalKeyboardModule.mm +3 -3
  24. package/ios/Services/RNCEKVFocusLinkObserver.h +7 -1
  25. package/ios/Services/RNCEKVFocusLinkObserver.mm +31 -6
  26. package/ios/Services/RNCEKVKeyboardOrderManager/RNCEKVKeyboardOrderManager.h +17 -0
  27. package/ios/Services/RNCEKVKeyboardOrderManager/RNCEKVKeyboardOrderManager.mm +15 -0
  28. package/ios/Services/{RNCEKVRelashioship.h → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVOrderRelationship.h} +8 -7
  29. package/ios/Services/{RNCEKVRelashioship.mm → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVOrderRelationship.mm} +36 -13
  30. package/ios/Services/RNCEKVOrderLinking.h +2 -7
  31. package/ios/Services/RNCEKVOrderLinking.mm +27 -64
  32. package/ios/Services/RNCEKVOrderSubscriber.h +4 -3
  33. package/ios/Services/RNCEKVOrderSubscriber.mm +2 -1
  34. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockView.h +38 -0
  35. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockView.mm +62 -0
  36. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockViewManager.h +14 -0
  37. package/ios/Views/RNCEKVExternalKeyboardLockView/RNCEKVExternalKeyboardLockViewManager.mm +25 -0
  38. package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardView.mm +2 -2
  39. package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroup.mm +0 -1
  40. package/ios/Views/RNCEKVTextInputFocusWrapper/RNCEKVTextInputFocusWrapper.mm +1 -15
  41. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js +21 -0
  42. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js.map +1 -0
  43. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.js +11 -0
  44. package/lib/commonjs/components/KeyboardFocusLock/FocusFrame/FocusFrame.js.map +1 -0
  45. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js +19 -0
  46. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js.map +1 -0
  47. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.js +15 -0
  48. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrap.js.map +1 -0
  49. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js +46 -0
  50. package/lib/commonjs/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js.map +1 -0
  51. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js +21 -0
  52. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js.map +1 -0
  53. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js +9 -0
  54. package/lib/commonjs/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js.map +1 -0
  55. package/lib/commonjs/context/FocusFrameProviderContext.js +28 -0
  56. package/lib/commonjs/context/FocusFrameProviderContext.js.map +1 -0
  57. package/lib/commonjs/index.js +7 -1
  58. package/lib/commonjs/index.js.map +1 -1
  59. package/lib/commonjs/nativeSpec/ExternalKeyboardLockViewNativeComponent.js +10 -0
  60. package/lib/commonjs/nativeSpec/ExternalKeyboardLockViewNativeComponent.js.map +1 -0
  61. package/lib/commonjs/types/KeyboardFocusLock.types.js +6 -0
  62. package/lib/commonjs/types/KeyboardFocusLock.types.js.map +1 -0
  63. package/lib/commonjs/utils/useKeyboardPress/useKeyboardPress.android.js +25 -12
  64. package/lib/commonjs/utils/useKeyboardPress/useKeyboardPress.android.js.map +1 -1
  65. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js +14 -0
  66. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.js.map +1 -0
  67. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.js +4 -0
  68. package/lib/module/components/KeyboardFocusLock/FocusFrame/FocusFrame.js.map +1 -0
  69. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js +12 -0
  70. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.js.map +1 -0
  71. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.js +8 -0
  72. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrap.js.map +1 -0
  73. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js +39 -0
  74. package/lib/module/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.js.map +1 -0
  75. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js +14 -0
  76. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.js.map +1 -0
  77. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js +3 -0
  78. package/lib/module/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.js.map +1 -0
  79. package/lib/module/context/FocusFrameProviderContext.js +20 -0
  80. package/lib/module/context/FocusFrameProviderContext.js.map +1 -0
  81. package/lib/module/index.js +6 -0
  82. package/lib/module/index.js.map +1 -1
  83. package/lib/module/nativeSpec/ExternalKeyboardLockViewNativeComponent.js +3 -0
  84. package/lib/module/nativeSpec/ExternalKeyboardLockViewNativeComponent.js.map +1 -0
  85. package/lib/module/types/KeyboardFocusLock.types.js +2 -0
  86. package/lib/module/types/KeyboardFocusLock.types.js.map +1 -0
  87. package/lib/module/utils/useKeyboardPress/useKeyboardPress.android.js +25 -12
  88. package/lib/module/utils/useKeyboardPress/useKeyboardPress.android.js.map +1 -1
  89. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.d.ts +4 -0
  90. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.d.ts.map +1 -0
  91. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.d.ts +3 -0
  92. package/lib/typescript/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.d.ts.map +1 -0
  93. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.d.ts +4 -0
  94. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.d.ts.map +1 -0
  95. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.d.ts +3 -0
  96. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.d.ts.map +1 -0
  97. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.d.ts +3 -0
  98. package/lib/typescript/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.d.ts.map +1 -0
  99. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.d.ts +4 -0
  100. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.d.ts.map +1 -0
  101. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.d.ts +3 -0
  102. package/lib/typescript/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.d.ts.map +1 -0
  103. package/lib/typescript/src/components/Touchable/Pressable.d.ts +1 -1
  104. package/lib/typescript/src/context/FocusFrameProviderContext.d.ts +12 -0
  105. package/lib/typescript/src/context/FocusFrameProviderContext.d.ts.map +1 -0
  106. package/lib/typescript/src/index.d.ts +4 -0
  107. package/lib/typescript/src/index.d.ts.map +1 -1
  108. package/lib/typescript/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.d.ts +9 -0
  109. package/lib/typescript/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.d.ts.map +1 -0
  110. package/lib/typescript/src/types/KeyboardFocusLock.types.d.ts +6 -0
  111. package/lib/typescript/src/types/KeyboardFocusLock.types.d.ts.map +1 -0
  112. package/lib/typescript/src/utils/useKeyboardPress/useKeyboardPress.android.d.ts.map +1 -1
  113. package/lib/typescript/src/utils/withKeyboardFocus.d.ts +1 -1
  114. package/package.json +6 -5
  115. package/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.android.tsx +18 -0
  116. package/src/components/KeyboardFocusLock/FocusFrame/FocusFrame.tsx +8 -0
  117. package/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.android.tsx +17 -0
  118. package/src/components/KeyboardFocusLock/FocusTrap/FocusTrap.tsx +9 -0
  119. package/src/components/KeyboardFocusLock/FocusTrap/FocusTrapMountWrapper.ts +40 -0
  120. package/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.android.tsx +16 -0
  121. package/src/components/KeyboardFocusLock/KeyboardFocusLockBase/KeyboardFocusLockBase.tsx +5 -0
  122. package/src/context/FocusFrameProviderContext.tsx +36 -0
  123. package/src/index.tsx +8 -0
  124. package/src/nativeSpec/ExternalKeyboardLockViewNativeComponent.ts +13 -0
  125. package/src/types/KeyboardFocusLock.types.ts +6 -0
  126. package/src/utils/useKeyboardPress/useKeyboardPress.android.ts +36 -12
  127. package/ios/Services/RNCEKVFocusLinkObserverManager.h +0 -23
  128. package/ios/Services/RNCEKVFocusLinkObserverManager.mm +0 -30
  129. /package/ios/Services/{RNCEKVSortedMap.h → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVSortedMap/RNCEKVSortedMap.h} +0 -0
  130. /package/ios/Services/{RNCEKVSortedMap.mm → RNCEKVKeyboardOrderManager/RNCEKVOrderRelationship/RNCEKVSortedMap/RNCEKVSortedMap.mm} +0 -0
package/README.md CHANGED
@@ -5,152 +5,59 @@ 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.
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" />
32
11
 
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
- ```
12
+ ## Features
59
13
 
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)
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.
61
19
 
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` |
20
+ ## New Release: Focus Lock
71
21
 
72
- ## Indexes Focus Order
22
+ | iOS | Android |
23
+ | :-- | :-- |
24
+ | <img src="/.github/images/rnek-focus-lock-ios.gif" height="500" /> | <img src="/.github/images/rnek-focus-lock-ios.gif" height="500" /> |
73
25
 
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.
26
+ > 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.
75
27
 
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 requres `orderGroup` param for proper order set, you can use `KeyboardOrderFocusGroup` or provide `orderGroup` to the component.
101
-
102
- ```tsx
103
- <Pressable
104
- orderGroup="main"
105
- onPress={onPress}
106
- orderIndex={2}
107
- >
108
- <Text>Back</Text>
109
- </Pressable>
110
- ```
28
+ <details>
29
+ <summary>More Information</summary>
111
30
 
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` |
31
+ - On iOS, `Focus.Trap` uses the native `accessibilityViewIsModal` property to keep the focus within a defined area.
32
+ - 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
33
 
34
+ #### How It Works
117
35
 
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)
36
+ The focus lock functionality should be used as a pair:
119
37
 
120
- ## Focus Lock
38
+ - `Focus.Frame`: This component is used at the root level of a "screen" to detect focus leaks and ensure that focus remains contained.
39
+ - `Focus.Trap`: This component wraps the content area where focus should be explicitly locked.
121
40
 
122
- Finally, you can lock focus to specific directions.
41
+ | Prop | Description |
42
+ | :-- | :-- |
43
+ | ViewProps | Includes all standard React Native View properties, such as style, testID, etc. |
123
44
 
124
45
  ```tsx
125
- <Pressable
126
- lockFocus={['down', 'right']}
127
- >
128
- <Text>Lock Example</Text>
129
- </Pressable>
46
+ <Focus.Frame>
47
+ ...
48
+ <Focus.Trap>
49
+ <Text accessibilityRole="header">Locked Area</Text>
50
+ <Button
51
+ title="Confirm"
52
+ accessibilityLabel="Confirm action"
53
+ />
54
+ </Focus.Trap>
55
+ ...
56
+ </Focus.Frame>
130
57
  ```
131
58
 
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
59
  </details>
140
60
 
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
61
  ## Installation
155
62
 
156
63
  ```sh
@@ -324,7 +231,7 @@ containerStyle | Style for the container | StyleProp<ViewStyle>
324
231
  containerFocusStyle?: | Style applied to the container when focused | `FocusStyle`
325
232
  tintType?: | Tint behavior type | `'default' \\| 'hover' \\| 'background' \\| 'none'`
326
233
  FocusHoverComponent?: | Component displayed on focus | `\\| ReactElement  \\| FunctionComponent  \\| (() => ReactElement);`
327
- onSubmitEditing?: | Extended `onSubmitEditing` for mulitline input | `(e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => void)`
234
+ onSubmitEditing?: | Extended `onSubmitEditing` for multiline input | `(e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => void)`
328
235
  ...rest | Remaining TextInput props  | `TextInputProps`
329
236
 
330
237
 
@@ -336,7 +243,7 @@ import { KeyboardExtendedBaseView } from 'react-native-external-keyboard';
336
243
  <KeyboardExtendedBaseView
337
244
  onKeyDownPress={...}
338
245
  onKeyUpPress={...}
339
- focussable
246
+ focusable
340
247
  >
341
248
  <Text>Content</Text>
342
249
  </KeyboardExtendedBaseView>
@@ -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
+
@@ -13,46 +13,83 @@
13
13
  #import "RNCEKVFocusEffectUtility.h"
14
14
 
15
15
  @implementation RNCEKVFocusDelegate{
16
- UIView<RNCEKVFocusProtocol>* _delegate;
16
+ UIView<RNCEKVFocusProtocol>* _delegate;
17
17
  }
18
18
 
19
19
  - (instancetype _Nonnull )initWithView:(UIView<RNCEKVFocusProtocol> *_Nonnull)delegate{
20
- self = [super init];
21
- if (self) {
22
- _delegate = delegate;
20
+ self = [super init];
21
+ if (self) {
22
+ _delegate = delegate;
23
+ }
24
+ return self;
25
+ }
26
+
27
+ - (UIView*)getFirstFocusable:(UIView*)view {
28
+ if(view.subviews.count == 0) return nil;
29
+ UIView* child = view.subviews[0];
30
+ if(child.canBecomeFocused) {
31
+ return child;
32
+ } else {
33
+ return [self getFirstFocusable: child];
34
+ }
35
+ }
36
+
37
+
38
+ - (UIView *)focusingViewForGestureHandler {
39
+ UIView *view = _delegate.subviews.firstObject;
40
+ // Handle the special case for RNGestureHandlerButtonComponentView
41
+ if (view && [NSStringFromClass([view class]) isEqualToString:@"RNGestureHandlerButtonComponentView"] &&
42
+ view.subviews.count > 0) {
43
+ return view.subviews.firstObject;
44
+ }
45
+ return nil;
46
+ }
47
+
48
+ - (UIView *)firstObject {
49
+ UIView *firstChild = _delegate.subviews.firstObject;
50
+ if (firstChild && firstChild.canBecomeFocused) {
51
+ return firstChild;
23
52
  }
24
- return self;
53
+ return nil;
25
54
  }
26
55
 
56
+
57
+
27
58
  // ToDo RNCEKV-2, Double check condition, count more then 1 means that a view can be a ViewGroup, bun when we use hover component it can be considered as ViewGroup instead of touchable component, it can be improved by flag, or by removing hover component from js implementation
28
- - (UIView*)getFocusingView {
29
- if(_delegate.isGroup) {
59
+ - (UIView *)getFocusingView {
60
+ if (_delegate.isGroup) {
30
61
  return _delegate;
31
62
  }
32
63
 
33
- if(_delegate.subviews.count > 0 && _delegate.subviews[0].canBecomeFocused) {
34
- return _delegate.subviews[0];
64
+ UIView *gestureHandlerView = [self focusingViewForGestureHandler];
65
+ if (gestureHandlerView) {
66
+ return gestureHandlerView;
67
+ }
68
+
69
+ UIView *firstObject = [self firstObject];
70
+ if (firstObject) {
71
+ return firstObject;
35
72
  }
36
73
 
37
74
  return _delegate;
38
75
  }
39
76
 
40
77
  - (BOOL)canBecomeFocused {
41
- if(!_delegate.canBeFocused) {
42
- return false;
43
- }
44
- return [self getFocusingView] == _delegate;
78
+ if(!_delegate.canBeFocused) {
79
+ return false;
80
+ }
81
+ return [self getFocusingView] == _delegate;
45
82
  }
46
83
 
47
84
  - (NSNumber*)isFocusChanged:(UIFocusUpdateContext *)context {
48
- UIView* view = [self getFocusingView];
49
- if(context.nextFocusedView == view) {
50
- return @YES;
51
- } else if (context.previouslyFocusedView == view) {
52
- return @NO;
53
- }
54
-
55
- return nil;
85
+ UIView* view = [self getFocusingView];
86
+ if(context.nextFocusedView == view) {
87
+ return @YES;
88
+ } else if (context.previouslyFocusedView == view) {
89
+ return @NO;
90
+ }
91
+
92
+ return nil;
56
93
  }
57
94
 
58
95
 
@@ -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 */