Skip to content

Commit dfa985d

Browse files
committed
TextInput edge cases
1 parent 7187c08 commit dfa985d

File tree

3 files changed

+154
-134
lines changed

3 files changed

+154
-134
lines changed

React/Views/RCTView.m

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
#import "RCTViewKeyboardEvent.h"
2727
#if TARGET_OS_OSX // [macOS
2828
#import "RCTTextView.h"
29+
#import <React/RCTSinglelineTextInputView.h>
30+
#import <React/RCTMultilineTextInputView.h>
31+
#import <React/RCTUITextField.h>
32+
2933
#endif // macOS]
3034

3135
RCT_MOCK_DEF(RCTView, RCTContentInsets);
@@ -1763,6 +1767,12 @@ - (BOOL)handleKeyboardEventModern:(NSEvent*)event {
17631767

17641768
// To ensure we only dispatch one keyboard event to JS, only dispatch it if we are the first responder.
17651769
BOOL isFirstResponder = self == [[self window] firstResponder];
1770+
if ([self isKindOfClass:[RCTSinglelineTextInputView class]]) {
1771+
isFirstResponder = [(RCTUITextField *)[(RCTSinglelineTextInputView *)self backedTextInputView] currentEditor] == [[self window] firstResponder];
1772+
}
1773+
if ([self isKindOfClass:[RCTMultilineTextInputView class]]) {
1774+
isFirstResponder = [(RCTSinglelineTextInputView *)self backedTextInputView] == [[self window] firstResponder];
1775+
}
17661776
if (isFirstResponder) {
17671777
RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyEventFromEvent:event reactTag:self.reactTag];
17681778
[_eventDispatcher sendEvent:keyboardEvent];

React/Views/RCTViewManager.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,10 +526,12 @@ - (RCTShadowView *)shadowView
526526
RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock)
527527
RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock)
528528
RCT_EXPORT_VIEW_PROPERTY(passthroughAllKeyEvents, BOOL)
529-
RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTDirectEventBlock) // macOS keyboard events
530-
RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTDirectEventBlock) // macOS keyboard events
529+
RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock)
530+
RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock)
531531
RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray<RCTHandledKey *>)
532532
RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray<RCTHandledKey *>)
533+
RCT_EXPORT_VIEW_PROPERTY(keyDownEvents, NSArray<RCTHandledKey *>)
534+
RCT_EXPORT_VIEW_PROPERTY(keyUpEvents, NSArray<RCTHandledKey *>)
533535

534536
#endif // macOS]
535537

packages/rn-tester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js

Lines changed: 140 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ const ReactNative = require('react-native');
1515
import {Platform} from 'react-native';
1616
import type {KeyEvent} from 'react-native/Libraries/Types/CoreEventTypes';
1717

18-
const {Button, ScrollView, StyleSheet, Switch, Text, TextInput, View} =
19-
ReactNative;
18+
const {Button, StyleSheet, Switch, Text, TextInput, View} = ReactNative;
2019

2120
const switchStyle = {
2221
alignItems: 'center',
@@ -116,140 +115,150 @@ function KeyboardEventExample(): React.Node {
116115
);
117116

118117
return (
119-
<ScrollView>
120-
<View style={{padding: 10}}>
121-
<Text>
122-
Key events are called when a component detects a key press.To tab
123-
between views on macOS: Enable System Preferences / Keyboard /
124-
Shortcuts > Use keyboard navigation to move focus between controls.
125-
</Text>
126-
<View>
127-
{Platform.OS === 'macos' ? (
128-
<>
129-
<View style={switchStyle}>
130-
<Text style={styles.title}>View</Text>
131-
<Switch value={showView} onValueChange={toggleShowView} />
132-
</View>
133-
{showView ? (
134-
<>
135-
<Text style={styles.text}>
136-
validKeysDown: [g, Escape, Enter, ArrowLeft]{'\n'}
137-
validKeysUp: [c, d]
138-
</Text>
139-
<View
140-
focusable={true}
141-
style={styles.row}
142-
passthroughAllKeyEvents={passthroughAllKeyEvents}
143-
validKeysDown={['g', 'Escape', 'Enter', 'ArrowLeft']}
144-
keyDownEvents={['g', 'Escape', 'Enter', 'ArrowLeft']}
145-
onKeyDown={handleKeyDown}
146-
validKeysUp={['c', 'd']}
147-
onKeyUp={handleKeyUp}
148-
/>
149-
</>
150-
) : null}
151-
<View style={switchStyle}>
152-
<Text style={styles.title}>TextInput</Text>
153-
<Switch
154-
value={showTextInput}
155-
onValueChange={toggleShowTextInput}
118+
<View style={{padding: 10}}>
119+
<Text>
120+
Key events are called when a component detects a key press.To tab
121+
between views on macOS: Enable System Preferences / Keyboard / Shortcuts
122+
> Use keyboard navigation to move focus between controls.
123+
</Text>
124+
<View>
125+
{Platform.OS === 'macos' ? (
126+
<>
127+
<View style={switchStyle}>
128+
<Text style={styles.title}>View</Text>
129+
<Switch value={showView} onValueChange={toggleShowView} />
130+
</View>
131+
{showView ? (
132+
<>
133+
<Text style={styles.text}>
134+
validKeysDown: [g, Escape, Enter, ArrowLeft]{'\n'}
135+
validKeysUp: [c, d]
136+
</Text>
137+
<View
138+
focusable={true}
139+
style={styles.row}
140+
passthroughAllKeyEvents={passthroughAllKeyEvents}
141+
validKeysDown={['g', 'Escape', 'Enter', 'ArrowLeft']}
142+
keyDownEvents={['g', 'Escape', 'Enter', 'ArrowLeft']}
143+
onKeyDown={handleKeyDown}
144+
validKeysUp={['c', 'd']}
145+
onKeyUp={handleKeyUp}
156146
/>
157-
</View>
158-
{showTextInput ? (
159-
<>
160-
<Text style={styles.text}>
161-
validKeysDown: [ArrowRight, ArrowDown, Ctrl+Enter]{'\n'}
162-
validKeysUp: [Escape, Enter]
163-
</Text>
164-
<TextInput
165-
blurOnSubmit={false}
166-
placeholder={'Singleline textInput'}
167-
multiline={false}
168-
focusable={true}
169-
style={styles.row}
170-
passthroughAllKeyEvents={passthroughAllKeyEvents}
171-
validKeysDown={[
172-
'ArrowRight',
173-
'ArrowDown',
174-
{key: 'Enter', ctrlKey: true},
175-
]}
176-
onKeyDown={handleKeyDown}
177-
validKeysUp={['Escape', 'Enter']}
178-
onKeyUp={handleKeyUp}
179-
/>
180-
<TextInput
181-
placeholder={'Multiline textInput'}
182-
multiline={true}
183-
focusable={true}
184-
style={styles.row}
185-
passthroughAllKeyEvents={passthroughAllKeyEvents}
186-
validKeysDown={[
187-
'ArrowRight',
188-
'ArrowDown',
189-
{key: 'Enter', ctrlKey: true},
190-
]}
191-
onKeyDown={handleKeyDown}
192-
validKeysUp={['Escape', 'Enter']}
193-
onKeyUp={handleKeyUp}
194-
/>
195-
</>
196-
) : null}
197-
<View style={switchStyle}>
198-
<Text style={styles.title}>TextInput with no handled keys</Text>
199-
<Switch
200-
value={showTextInput2}
201-
onValueChange={toggleShowTextInput2}
147+
</>
148+
) : null}
149+
<View style={switchStyle}>
150+
<Text style={styles.title}>TextInput</Text>
151+
<Switch
152+
value={showTextInput}
153+
onValueChange={toggleShowTextInput}
154+
/>
155+
</View>
156+
{showTextInput ? (
157+
<>
158+
<Text style={styles.text}>
159+
validKeysDown: [ArrowRight, ArrowDown, Ctrl+Enter]{'\n'}
160+
validKeysUp: [Escape, Enter]
161+
</Text>
162+
<TextInput
163+
blurOnSubmit={false}
164+
placeholder={'Singleline textInput'}
165+
multiline={false}
166+
focusable={true}
167+
style={styles.row}
168+
passthroughAllKeyEvents={passthroughAllKeyEvents}
169+
validKeysDown={[
170+
'ArrowRight',
171+
'ArrowDown',
172+
{key: 'Enter', ctrlKey: true},
173+
]}
174+
keyDownEvents={[
175+
{key: 'ArrowRight'},
176+
{key: 'ArrowDown'},
177+
{key: 'Enter', ctrlKey: true},
178+
]}
179+
onKeyDown={handleKeyDown}
180+
validKeysUp={['Escape', 'Enter']}
181+
onKeyUp={handleKeyUp}
202182
/>
203-
</View>
204-
{showTextInput2 ? (
205-
<>
206-
<Text style={styles.text}>
207-
validKeysDown: []{'\n'}
208-
validKeysUp: []
209-
</Text>
210-
<TextInput
211-
blurOnSubmit={false}
212-
placeholder={'Singleline textInput'}
213-
multiline={false}
214-
focusable={true}
215-
style={styles.row}
216-
passthroughAllKeyEvents={passthroughAllKeyEvents}
217-
validKeysDown={[]}
218-
onKeyDown={handleKeyDown}
219-
validKeysUp={[]}
220-
onKeyUp={handleKeyUp}
221-
/>
222-
<TextInput
223-
placeholder={'Multiline textInput'}
224-
multiline={true}
225-
focusable={true}
226-
style={styles.row}
227-
passthroughAllKeyEvents={passthroughAllKeyEvents}
228-
validKeysDown={[]}
229-
onKeyDown={handleKeyDown}
230-
validKeysUp={[]}
231-
onKeyUp={handleKeyUp}
232-
/>
233-
</>
234-
) : null}
235-
</>
236-
) : null}
237-
<View style={switchStyle}>
238-
<Text>{'Pass through all key events'}</Text>
239-
<Switch
240-
value={passthroughAllKeyEvents}
241-
onValueChange={toggleSwitch}
242-
/>
243-
</View>
244-
<Button
245-
testID="event_clear_button"
246-
onPress={clearLog}
247-
title="Clear event log"
183+
<TextInput
184+
placeholder={'Multiline textInput'}
185+
multiline={true}
186+
focusable={true}
187+
style={styles.row}
188+
passthroughAllKeyEvents={passthroughAllKeyEvents}
189+
validKeysDown={[
190+
'ArrowRight',
191+
'ArrowDown',
192+
{key: 'Enter', ctrlKey: true},
193+
]}
194+
keyDownEvents={[
195+
{key: 'ArrowRight'},
196+
{key: 'ArrowDown'},
197+
{key: 'Enter', ctrlKey: true},
198+
]}
199+
onKeyDown={handleKeyDown}
200+
validKeysUp={['Escape', 'Enter']}
201+
onKeyUp={handleKeyUp}
202+
/>
203+
</>
204+
) : null}
205+
<View style={switchStyle}>
206+
<Text style={styles.title}>TextInput with no handled keys</Text>
207+
<Switch
208+
value={showTextInput2}
209+
onValueChange={toggleShowTextInput2}
210+
/>
211+
</View>
212+
{showTextInput2 ? (
213+
<>
214+
<Text style={styles.text}>
215+
validKeysDown: []{'\n'}
216+
validKeysUp: []
217+
</Text>
218+
<TextInput
219+
blurOnSubmit={false}
220+
placeholder={'Singleline textInput'}
221+
multiline={false}
222+
focusable={true}
223+
style={styles.row}
224+
passthroughAllKeyEvents={passthroughAllKeyEvents}
225+
validKeysDown={[]}
226+
keyDownEvents={[]}
227+
onKeyDown={handleKeyDown}
228+
validKeysUp={[]}
229+
onKeyUp={handleKeyUp}
230+
/>
231+
<TextInput
232+
placeholder={'Multiline textInput'}
233+
multiline={true}
234+
focusable={true}
235+
style={styles.row}
236+
passthroughAllKeyEvents={passthroughAllKeyEvents}
237+
validKeysDown={[]}
238+
keyDownEvents={[]}
239+
onKeyDown={handleKeyDown}
240+
validKeysUp={[]}
241+
onKeyUp={handleKeyUp}
242+
/>
243+
</>
244+
) : null}
245+
</>
246+
) : null}
247+
<View style={switchStyle}>
248+
<Text>{'Pass through all key events'}</Text>
249+
<Switch
250+
value={passthroughAllKeyEvents}
251+
onValueChange={toggleSwitch}
248252
/>
249-
<Text>{'Events:\n' + log.join('\n')}</Text>
250253
</View>
254+
<Button
255+
testID="event_clear_button"
256+
onPress={clearLog}
257+
title="Clear event log"
258+
/>
259+
<Text>{'Events:\n' + log.join('\n')}</Text>
251260
</View>
252-
</ScrollView>
261+
</View>
253262
);
254263
}
255264

@@ -287,5 +296,4 @@ exports.examples = [
287296
return <KeyboardEventExample />;
288297
},
289298
},
290-
291299
];

0 commit comments

Comments
 (0)