react-native-universal-keyboard-aware-scrollview 1.0.2 → 1.0.3
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 +145 -148
- package/package.json +1 -1
- package/src/NativeModule.ts +45 -41
- package/src/components/KeyboardAwareScrollView.tsx +258 -357
- package/src/hooks/index.ts +5 -1
- package/src/hooks/useKeyboard.ts +65 -305
- package/src/index.ts +13 -16
- package/src/types.ts +30 -67
- package/src/utils/KeyboardController.ts +10 -97
package/README.md
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
# react-native-universal-keyboard-aware-scrollview
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/react-native-universal-keyboard-aware-scrollview)
|
|
4
|
-
[](https://github.com/AetherTechDev/react-native-universal-keyboard-aware-scrollview/blob/main/LICENSE)
|
|
5
4
|
|
|
6
|
-
A **universal keyboard-aware ScrollView** for React Native that **
|
|
7
|
-
- ✅ Normal screens
|
|
8
|
-
- ✅ React Native Modal
|
|
9
|
-
- ✅ BottomSheet components
|
|
10
|
-
- ✅ Multiline TextInput (textarea)
|
|
11
|
-
- ✅ Any overlay or dialog scenario
|
|
5
|
+
A **universal keyboard-aware ScrollView** for React Native that **automatically scrolls** to keep the focused input visible when the keyboard appears.
|
|
12
6
|
|
|
13
|
-
##
|
|
7
|
+
## ✅ Works With
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
- Normal screens
|
|
10
|
+
- React Native Modal
|
|
11
|
+
- Bottom sheets
|
|
12
|
+
- **Single-line TextInput**
|
|
13
|
+
- **Multiline TextInput (textarea)**
|
|
20
14
|
|
|
21
15
|
## 📦 Installation
|
|
22
16
|
|
|
@@ -26,254 +20,257 @@ npm install react-native-universal-keyboard-aware-scrollview
|
|
|
26
20
|
|
|
27
21
|
### iOS Setup
|
|
28
22
|
```bash
|
|
29
|
-
cd ios && pod install
|
|
23
|
+
cd ios && pod install && cd ..
|
|
30
24
|
```
|
|
31
25
|
|
|
32
26
|
### Android Setup
|
|
33
|
-
No additional setup
|
|
27
|
+
No additional setup needed (auto-linking).
|
|
34
28
|
|
|
35
|
-
### Expo
|
|
29
|
+
### Expo
|
|
36
30
|
```bash
|
|
37
31
|
npx expo prebuild
|
|
38
32
|
npx expo run:ios # or run:android
|
|
39
33
|
```
|
|
40
34
|
|
|
41
|
-
> **Note:** This package
|
|
35
|
+
> ⚠️ **Note:** This package has native code and won't work in Expo Go. Use a development build.
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
---
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
## 🚀 Usage
|
|
40
|
+
|
|
41
|
+
### Basic Example
|
|
46
42
|
|
|
47
43
|
```tsx
|
|
48
44
|
import React from 'react';
|
|
49
|
-
import { TextInput, StyleSheet, SafeAreaView } from 'react-native';
|
|
45
|
+
import { TextInput, StyleSheet, SafeAreaView, Text } from 'react-native';
|
|
50
46
|
import { KeyboardAwareScrollView } from 'react-native-universal-keyboard-aware-scrollview';
|
|
51
47
|
|
|
52
48
|
export default function App() {
|
|
53
49
|
return (
|
|
54
50
|
<SafeAreaView style={styles.container}>
|
|
55
|
-
<KeyboardAwareScrollView
|
|
51
|
+
<KeyboardAwareScrollView
|
|
52
|
+
style={styles.scroll}
|
|
53
|
+
extraScrollHeight={75}
|
|
54
|
+
>
|
|
55
|
+
<Text style={styles.title}>Contact Form</Text>
|
|
56
|
+
|
|
56
57
|
<TextInput placeholder="Name" style={styles.input} />
|
|
57
|
-
<TextInput placeholder="Email" style={styles.input} />
|
|
58
|
-
<TextInput placeholder="Phone" style={styles.input} />
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
<TextInput placeholder="Email" style={styles.input} keyboardType="email-address" />
|
|
59
|
+
<TextInput placeholder="Phone" style={styles.input} keyboardType="phone-pad" />
|
|
60
|
+
|
|
61
|
+
{/* Multiline TextInput - automatically handled! */}
|
|
62
|
+
<TextInput
|
|
63
|
+
placeholder="Your message..."
|
|
64
|
+
style={[styles.input, styles.textArea]}
|
|
65
|
+
multiline
|
|
66
|
+
numberOfLines={6}
|
|
67
|
+
textAlignVertical="top"
|
|
64
68
|
/>
|
|
69
|
+
|
|
70
|
+
<TextInput placeholder="Website (optional)" style={styles.input} />
|
|
65
71
|
</KeyboardAwareScrollView>
|
|
66
72
|
</SafeAreaView>
|
|
67
73
|
);
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
const styles = StyleSheet.create({
|
|
71
|
-
container: {
|
|
72
|
-
|
|
77
|
+
container: {
|
|
78
|
+
flex: 1,
|
|
79
|
+
backgroundColor: '#f5f5f5'
|
|
80
|
+
},
|
|
81
|
+
scroll: {
|
|
82
|
+
flex: 1,
|
|
83
|
+
padding: 20
|
|
84
|
+
},
|
|
85
|
+
title: {
|
|
86
|
+
fontSize: 24,
|
|
87
|
+
fontWeight: 'bold',
|
|
88
|
+
marginBottom: 20
|
|
89
|
+
},
|
|
73
90
|
input: {
|
|
91
|
+
backgroundColor: 'white',
|
|
74
92
|
borderWidth: 1,
|
|
75
|
-
borderColor: '#
|
|
93
|
+
borderColor: '#ddd',
|
|
76
94
|
borderRadius: 8,
|
|
77
|
-
padding:
|
|
78
|
-
marginBottom:
|
|
95
|
+
padding: 15,
|
|
96
|
+
marginBottom: 15,
|
|
97
|
+
fontSize: 16,
|
|
98
|
+
},
|
|
99
|
+
textArea: {
|
|
100
|
+
height: 150,
|
|
101
|
+
textAlignVertical: 'top',
|
|
79
102
|
},
|
|
80
|
-
multiline: { height: 120, textAlignVertical: 'top' },
|
|
81
103
|
});
|
|
82
104
|
```
|
|
83
105
|
|
|
84
|
-
###
|
|
106
|
+
### Inside Modal
|
|
85
107
|
|
|
86
108
|
```tsx
|
|
87
109
|
import React, { useState } from 'react';
|
|
88
|
-
import { Modal, TextInput, View,
|
|
110
|
+
import { Modal, TextInput, Button, SafeAreaView, View, Text, StyleSheet } from 'react-native';
|
|
89
111
|
import { KeyboardAwareScrollView } from 'react-native-universal-keyboard-aware-scrollview';
|
|
90
112
|
|
|
91
113
|
export default function ModalExample() {
|
|
92
114
|
const [visible, setVisible] = useState(false);
|
|
93
115
|
|
|
94
116
|
return (
|
|
95
|
-
|
|
96
|
-
<Button title="Open Modal" onPress={() => setVisible(true)} />
|
|
97
|
-
|
|
117
|
+
<View style={styles.container}>
|
|
118
|
+
<Button title="Open Modal Form" onPress={() => setVisible(true)} />
|
|
119
|
+
|
|
98
120
|
<Modal visible={visible} animationType="slide">
|
|
99
|
-
<SafeAreaView style={styles.
|
|
121
|
+
<SafeAreaView style={styles.modal}>
|
|
122
|
+
<Text style={styles.title}>Modal Form</Text>
|
|
123
|
+
|
|
100
124
|
<KeyboardAwareScrollView
|
|
125
|
+
style={styles.scroll}
|
|
101
126
|
insideModal={true}
|
|
102
|
-
extraScrollHeight={
|
|
127
|
+
extraScrollHeight={80}
|
|
103
128
|
>
|
|
104
|
-
<TextInput placeholder="
|
|
129
|
+
<TextInput placeholder="Username" style={styles.input} />
|
|
105
130
|
<TextInput placeholder="Email" style={styles.input} />
|
|
106
|
-
<TextInput
|
|
107
|
-
|
|
108
|
-
|
|
131
|
+
<TextInput placeholder="Password" style={styles.input} secureTextEntry />
|
|
132
|
+
|
|
133
|
+
<TextInput
|
|
134
|
+
placeholder="Bio (multiline)"
|
|
135
|
+
style={[styles.input, { height: 120 }]}
|
|
109
136
|
multiline
|
|
110
|
-
|
|
137
|
+
textAlignVertical="top"
|
|
111
138
|
/>
|
|
112
139
|
</KeyboardAwareScrollView>
|
|
140
|
+
|
|
113
141
|
<Button title="Close" onPress={() => setVisible(false)} />
|
|
114
142
|
</SafeAreaView>
|
|
115
143
|
</Modal>
|
|
116
|
-
|
|
144
|
+
</View>
|
|
117
145
|
);
|
|
118
146
|
}
|
|
119
147
|
|
|
120
148
|
const styles = StyleSheet.create({
|
|
121
|
-
container: { flex: 1 },
|
|
149
|
+
container: { flex: 1, justifyContent: 'center', padding: 20 },
|
|
150
|
+
modal: { flex: 1 },
|
|
151
|
+
title: { fontSize: 20, fontWeight: 'bold', padding: 20 },
|
|
152
|
+
scroll: { flex: 1, padding: 20 },
|
|
122
153
|
input: {
|
|
154
|
+
backgroundColor: 'white',
|
|
123
155
|
borderWidth: 1,
|
|
124
156
|
borderColor: '#ccc',
|
|
125
157
|
borderRadius: 8,
|
|
126
158
|
padding: 12,
|
|
127
|
-
|
|
159
|
+
marginBottom: 12,
|
|
160
|
+
fontSize: 16,
|
|
128
161
|
},
|
|
129
|
-
multiline: { height: 100, textAlignVertical: 'top' },
|
|
130
162
|
});
|
|
131
163
|
```
|
|
132
164
|
|
|
133
|
-
### Multiline TextInput (Textarea) Support
|
|
134
|
-
|
|
135
|
-
The component automatically detects multiline TextInputs and provides extra scroll space:
|
|
136
|
-
|
|
137
|
-
```tsx
|
|
138
|
-
<KeyboardAwareScrollView
|
|
139
|
-
extraHeightForMultiline={100} // Extra space for multiline inputs
|
|
140
|
-
>
|
|
141
|
-
<TextInput
|
|
142
|
-
placeholder="Write your message..."
|
|
143
|
-
multiline
|
|
144
|
-
numberOfLines={6}
|
|
145
|
-
style={{ height: 150, textAlignVertical: 'top' }}
|
|
146
|
-
/>
|
|
147
|
-
</KeyboardAwareScrollView>
|
|
148
|
-
```
|
|
149
|
-
|
|
150
165
|
### Using the Hook
|
|
151
166
|
|
|
152
167
|
```tsx
|
|
168
|
+
import React from 'react';
|
|
169
|
+
import { View, TextInput, Button, Text, StyleSheet } from 'react-native';
|
|
153
170
|
import { useKeyboard } from 'react-native-universal-keyboard-aware-scrollview';
|
|
154
171
|
|
|
155
|
-
function
|
|
156
|
-
const {
|
|
157
|
-
keyboardHeight,
|
|
158
|
-
isKeyboardVisible,
|
|
159
|
-
dismissKeyboard
|
|
160
|
-
} = useKeyboard();
|
|
172
|
+
export default function HookExample() {
|
|
173
|
+
const { keyboardHeight, isKeyboardVisible, dismissKeyboard } = useKeyboard();
|
|
161
174
|
|
|
162
175
|
return (
|
|
163
|
-
<View style={{ paddingBottom: keyboardHeight }}>
|
|
164
|
-
<
|
|
176
|
+
<View style={[styles.container, { paddingBottom: keyboardHeight }]}>
|
|
177
|
+
<Text>Keyboard Height: {keyboardHeight}px</Text>
|
|
178
|
+
<Text>Visible: {isKeyboardVisible ? 'Yes' : 'No'}</Text>
|
|
179
|
+
|
|
180
|
+
<TextInput placeholder="Type something..." style={styles.input} />
|
|
181
|
+
|
|
165
182
|
{isKeyboardVisible && (
|
|
166
|
-
<Button title="Dismiss" onPress={dismissKeyboard} />
|
|
183
|
+
<Button title="Dismiss Keyboard" onPress={dismissKeyboard} />
|
|
167
184
|
)}
|
|
168
185
|
</View>
|
|
169
186
|
);
|
|
170
187
|
}
|
|
188
|
+
|
|
189
|
+
const styles = StyleSheet.create({
|
|
190
|
+
container: { flex: 1, padding: 20 },
|
|
191
|
+
input: { borderWidth: 1, borderColor: '#ccc', padding: 12, marginVertical: 20 },
|
|
192
|
+
});
|
|
171
193
|
```
|
|
172
194
|
|
|
173
|
-
|
|
195
|
+
---
|
|
174
196
|
|
|
175
|
-
|
|
197
|
+
## 📖 Props
|
|
176
198
|
|
|
177
199
|
| Prop | Type | Default | Description |
|
|
178
200
|
|------|------|---------|-------------|
|
|
179
|
-
| `enableOnAndroid` |
|
|
180
|
-
| `enableOnIOS` |
|
|
181
|
-
| `extraScrollHeight` |
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
|
|
189
|
-
### `useKeyboard` Hook
|
|
201
|
+
| `enableOnAndroid` | boolean | `true` | Enable on Android |
|
|
202
|
+
| `enableOnIOS` | boolean | `true` | Enable on iOS |
|
|
203
|
+
| `extraScrollHeight` | number | `75` | Extra scroll padding above keyboard |
|
|
204
|
+
| `enableAutoScrollToFocused` | boolean | `true` | Auto-scroll to focused input |
|
|
205
|
+
| `insideModal` | boolean | `false` | Set true when inside Modal |
|
|
206
|
+
| `keyboardShouldPersistTaps` | string | `'handled'` | Keyboard tap behavior |
|
|
207
|
+
| `resetScrollToCoords` | object | `null` | Reset scroll on keyboard hide |
|
|
208
|
+
| `onKeyboardDidShow` | function | - | Called when keyboard shows |
|
|
209
|
+
| `onKeyboardDidHide` | function | - | Called when keyboard hides |
|
|
190
210
|
|
|
191
|
-
|
|
192
|
-
const {
|
|
193
|
-
keyboardHeight, // Current keyboard height (number)
|
|
194
|
-
isKeyboardVisible, // Is keyboard showing (boolean)
|
|
195
|
-
dismissKeyboard, // Function to dismiss keyboard
|
|
196
|
-
screenHeight, // Screen height
|
|
197
|
-
safeAreaBottom, // Safe area inset (iOS)
|
|
198
|
-
} = useKeyboard(options);
|
|
199
|
-
```
|
|
211
|
+
---
|
|
200
212
|
|
|
201
|
-
|
|
213
|
+
## 🔧 Ref Methods
|
|
202
214
|
|
|
203
215
|
```tsx
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
enableOnIOS: true,
|
|
207
|
-
onKeyboardDidShow: (event) => {},
|
|
208
|
-
onKeyboardDidHide: (event) => {},
|
|
209
|
-
onKeyboardHeightChange: (height) => {},
|
|
210
|
-
});
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### `KeyboardController` Utility
|
|
216
|
+
import { useRef } from 'react';
|
|
217
|
+
import { KeyboardAwareScrollView, KeyboardAwareScrollViewRef } from 'react-native-universal-keyboard-aware-scrollview';
|
|
214
218
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// Dismiss keyboard
|
|
219
|
-
await KeyboardController.dismiss();
|
|
219
|
+
function MyComponent() {
|
|
220
|
+
const scrollRef = useRef<KeyboardAwareScrollViewRef>(null);
|
|
220
221
|
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
return (
|
|
223
|
+
<KeyboardAwareScrollView ref={scrollRef}>
|
|
224
|
+
{/* Your inputs */}
|
|
225
|
+
</KeyboardAwareScrollView>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
223
228
|
|
|
224
|
-
//
|
|
225
|
-
|
|
229
|
+
// Available methods:
|
|
230
|
+
// scrollRef.current?.scrollTo({ x: 0, y: 100, animated: true });
|
|
231
|
+
// scrollRef.current?.scrollToEnd({ animated: true });
|
|
232
|
+
// scrollRef.current?.scrollToInput(inputRef);
|
|
233
|
+
// scrollRef.current?.getScrollView();
|
|
226
234
|
```
|
|
227
235
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
| Problem | Other Libraries | This Package |
|
|
231
|
-
|---------|----------------|--------------|
|
|
232
|
-
| Keyboard overlaps input in Modal | ❌ | ✅ |
|
|
233
|
-
| Multiline TextInput not working | ❌ | ✅ |
|
|
234
|
-
| Android resize glitches | ❌ | ✅ |
|
|
235
|
-
| Inconsistent heights | ❌ | ✅ |
|
|
236
|
-
| Race conditions | ❌ | ✅ |
|
|
236
|
+
---
|
|
237
237
|
|
|
238
|
-
|
|
238
|
+
## ✅ Supported Platforms
|
|
239
239
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
240
|
+
| Platform | Supported |
|
|
241
|
+
|----------|-----------|
|
|
242
|
+
| iOS | ✅ |
|
|
243
|
+
| Android | ✅ |
|
|
244
|
+
| React Native CLI | ✅ |
|
|
245
|
+
| Expo (Development Build) | ✅ |
|
|
246
|
+
| Expo Go | ❌ |
|
|
243
247
|
|
|
244
|
-
|
|
248
|
+
---
|
|
245
249
|
|
|
246
250
|
## 🐛 Troubleshooting
|
|
247
251
|
|
|
248
|
-
###
|
|
249
|
-
|
|
252
|
+
### Keyboard not detected
|
|
250
253
|
```bash
|
|
251
|
-
# iOS
|
|
254
|
+
# iOS - reinstall pods
|
|
252
255
|
cd ios && pod install --repo-update && cd ..
|
|
253
256
|
|
|
254
257
|
# Android - clean build
|
|
255
258
|
cd android && ./gradlew clean && cd ..
|
|
256
259
|
```
|
|
257
260
|
|
|
258
|
-
###
|
|
259
|
-
|
|
260
|
-
This package requires native code. Use:
|
|
261
|
-
```bash
|
|
262
|
-
npx expo prebuild
|
|
263
|
-
npx expo run:ios # or npx expo run:android
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
### Multiline TextInput not scrolling properly
|
|
267
|
-
|
|
261
|
+
### Multiline TextInput not scrolling
|
|
268
262
|
Make sure you're using the `multiline` prop:
|
|
269
263
|
```tsx
|
|
270
|
-
<TextInput
|
|
271
|
-
multiline
|
|
264
|
+
<TextInput
|
|
265
|
+
multiline={true} // Required!
|
|
272
266
|
numberOfLines={4}
|
|
267
|
+
textAlignVertical="top" // For Android
|
|
273
268
|
style={{ height: 100 }}
|
|
274
269
|
/>
|
|
275
270
|
```
|
|
276
271
|
|
|
272
|
+
---
|
|
273
|
+
|
|
277
274
|
## 📄 License
|
|
278
275
|
|
|
279
|
-
MIT ©
|
|
276
|
+
MIT © Vijay Kishan
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-universal-keyboard-aware-scrollview",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A universal keyboard-aware ScrollView for React Native that works correctly in normal screens, modals, and bottom sheets on both Android and iOS",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
package/src/NativeModule.ts
CHANGED
|
@@ -1,61 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Module wrapper
|
|
3
|
+
*
|
|
4
|
+
* This file provides access to the native keyboard module when available.
|
|
5
|
+
* Falls back gracefully to React Native's Keyboard API when native module is not linked.
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
import { NativeModules, NativeEventEmitter, Platform } from 'react-native';
|
|
2
|
-
import type { UniversalKeyboardNativeModule, KeyboardEvent } from './types';
|
|
3
9
|
|
|
4
10
|
const LINKING_ERROR =
|
|
5
11
|
`The package 'react-native-universal-keyboard-aware-scrollview' doesn't seem to be linked. Make sure: \n\n` +
|
|
6
12
|
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
|
|
7
13
|
'- You rebuilt the app after installing the package\n' +
|
|
8
|
-
'- You are not using Expo Go (use development build instead)\n'
|
|
14
|
+
'- You are not using Expo Go (use development build instead)\n\n' +
|
|
15
|
+
'The package will use React Native Keyboard API as fallback.';
|
|
9
16
|
|
|
10
17
|
/**
|
|
11
|
-
* Native module
|
|
18
|
+
* Native module interface
|
|
12
19
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
interface UniversalKeyboardNativeModule {
|
|
21
|
+
startListening(): Promise<boolean>;
|
|
22
|
+
stopListening(): Promise<boolean>;
|
|
23
|
+
getKeyboardHeight(): Promise<number>;
|
|
24
|
+
isKeyboardVisible(): Promise<boolean>;
|
|
25
|
+
dismissKeyboard(): Promise<boolean>;
|
|
26
|
+
addListener(eventName: string): void;
|
|
27
|
+
removeListeners(count: number): void;
|
|
28
|
+
}
|
|
15
29
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/
|
|
19
|
-
export const UniversalKeyboardModule: UniversalKeyboardNativeModule = NativeModule
|
|
20
|
-
? NativeModule
|
|
21
|
-
: new Proxy({} as UniversalKeyboardNativeModule, {
|
|
22
|
-
get() {
|
|
23
|
-
throw new Error(LINKING_ERROR);
|
|
24
|
-
},
|
|
25
|
-
});
|
|
30
|
+
// Get native module
|
|
31
|
+
const NativeModule = NativeModules.UniversalKeyboard as UniversalKeyboardNativeModule | undefined;
|
|
26
32
|
|
|
27
33
|
/**
|
|
28
|
-
*
|
|
34
|
+
* Check if native module is available
|
|
29
35
|
*/
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
export function isNativeModuleAvailable(): boolean {
|
|
37
|
+
return NativeModule != null;
|
|
38
|
+
}
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
|
-
*
|
|
36
|
-
* @param eventName - Name of the event to subscribe to
|
|
37
|
-
* @param callback - Callback function to execute when event fires
|
|
38
|
-
* @returns Cleanup function to unsubscribe
|
|
41
|
+
* Native module with fallback
|
|
39
42
|
*/
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
callback: (event: KeyboardEvent) => void
|
|
43
|
-
): () => void {
|
|
44
|
-
if (!KeyboardEventEmitter) {
|
|
43
|
+
export const UniversalKeyboardModule: UniversalKeyboardNativeModule = NativeModule || {
|
|
44
|
+
startListening: async () => {
|
|
45
45
|
console.warn(LINKING_ERROR);
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
46
|
+
return false;
|
|
47
|
+
},
|
|
48
|
+
stopListening: async () => false,
|
|
49
|
+
getKeyboardHeight: async () => 0,
|
|
50
|
+
isKeyboardVisible: async () => false,
|
|
51
|
+
dismissKeyboard: async () => {
|
|
52
|
+
const { Keyboard } = require('react-native');
|
|
53
|
+
Keyboard.dismiss();
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
56
|
+
addListener: () => {},
|
|
57
|
+
removeListeners: () => {},
|
|
58
|
+
};
|
|
55
59
|
|
|
56
60
|
/**
|
|
57
|
-
*
|
|
61
|
+
* Event emitter for native keyboard events
|
|
58
62
|
*/
|
|
59
|
-
export
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
export const KeyboardEventEmitter = NativeModule
|
|
64
|
+
? new NativeEventEmitter(NativeModule as any)
|
|
65
|
+
: null;
|